Estimate effective population size (Ne) of PWS from allele frequncy chagnes

source("../Rscripts/BaseScripts.R")
require(data.table)
require(plyr)
require(RColorBrewer)
library(poolSeq)
library(data.table)

Nest/PoolSeq package is used.

Ref: doi: 10.1534/genetics.116.191197

  1. Subset VCF files by population
#subset a VCF file by population (subset_vcf_byPopPWS.sh)

#!/bin/bash
#SBATCH --job-name=subsetPop
#SBATCH --mem=16G 
#SBATCH --nodes=4 
#SBATCH --ntasks=8 
#SBATCH -e subsetPop.err  
#SBATCH --time=72:00:00  
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL

#SBATCH -p high  

module load bcftools

bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/PWS07.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly07_maf05.vcf.gz 
bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/PWS17.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly17_maf05.vcf.gz 
bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/PWS91.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly91_maf05.vcf.gz 
bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/PWS96.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly96_maf05.vcf.gz 
  1. Calculate allele frequency using ANGSD
#Calculate allele frequency using VCFtools (calculateAF_VCFtools.sh)

#!/bin/bash -l
#SBATCH --job-name=calcAF
#SBATCH --mem=16G
#SBATCH --nodes=4 
#SBATCH --ntasks=8 
#SBATCH --error calcAF.err
#SBATCH --time=48:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high 

module load angsd

angsd -out /home/ktist/ph/data/angsd/AF/PWS91 -fai /home/jamcgirr/ph/data/c_harengus/c.harengus.fa.fai -doGlf 2 -doMaf 3 -doMajorMinor 4 -doPost 1 -doGeno 2 -vcf-pl /home/ktist/ph/data/new_vcf/MD7000/population/PWS91_maf05.vcf.gz -ref /home/jamcgirr/ph/data/c_harengus/c.harengus.fa 
  1. Obtain read depths from VCF files
#Obtain depth information from VCF files (extract_coveragePWS.sh)

#!/bin/bash
#SBATCH --job-name=extract_coverage 
#SBATCH --mem=16G 
#SBATCH --ntasks=1 
#SBATCH -e extract_coverage.err  
#SBATCH --time=48:00:00  
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high  

module load bcftools
bcftools query -f '%CHROM  %POS  %INFO/DP\n' /home/ktist/ph/data/new_vcf/MD7000/population/PWS07_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/depth/PWS07_maf05.depth.info 

Use poolSeq to calcualte Ne

1. Read AF (frq) files and filter out extreme values and uninformative loci

pops<-c("PWS91","PWS96","PWS07","PWS17")
yr<-c(91,96,"07",17)

#Read the allele freq data for PWS and trim for unlinked loci
unlnk<-fread('../Data/plink/prune/prune_50.5.0.5.prune.in')
setnames(unlnk, c("chromo","position"))
setkey(unlnk, chromo, position)
for (i in 1:length(pops)){
    df<-fread(paste0("../Data/new_vcf/AF/",pops[i],".mafs.gz"))
    df<-df[,c(1,2,6)]
    setkey(df, chromo, position)
    df<-merge(df, unlnk)
    assign(paste0("pws",i),df)
}


#combine AF for all years
pws<-cbind(pws1, pws2[,3],pws3[,3],pws4[,3])
colnames(pws)<-c("chr","pos","F0","F1","F2","F3")
#write.csv(pws, "../Output/Ne/PWSonly_AF.csv")

#Read depth information
for (i in 1:length(pops)){
    df<-fread(paste0("../Data/new_vcf/depth/",pops[i],"_maf05.depth.info"))
    setnames(df, c("chromo","position","depth"))
    setkey(df,chromo,position)
    df<-merge(df, unlnk)
    assign(paste0("D",i),df)
}
#combine Depth for all years
DP<-cbind(D1, D2[,3],D3[,3],D4[,3])
colnames(DP)<-c("chr","pos","F0","F1","F2","F3")
#write.csv(DP,"../Output/Ne/PWSonly_read_depth.csv")

#Find SNPs with extreme values and uninformative loci and remove them
retain<-checkSNP(pws[,"F0"],pws[,"F3"],DP[,"F0"], DP[,"F3"])
length(retain[retain==F]) #1180 will be removed

#filtered the snp dataset
pws_filtered<-pws[as.vector(retain),]
DP_filtered<-DP[as.vector(retain),]

#Look at F0 and F1
retain1<-checkSNP(pws_filtered[,"F0"],pws_filtered[,"F1"],DP_filtered[,"F0"], DP_filtered[,"F1"])
length(retain1[retain1==F]) #0

retain2<-checkSNP(pws_filtered[,"F0"],pws_filtered[,"F2"],DP_filtered[,"F0"], DP_filtered[,"F2"])
length(retain2[retain2==F]) #0

retain3<-checkSNP(pws_filtered[,"F1"],pws_filtered[,"F2"],DP_filtered[,"F1"], DP_filtered[,"F2"])
length(retain3[retain3==F]) #831

retain4<-checkSNP(pws_filtered[,"F2"],pws_filtered[,"F3"],DP_filtered[,"F2"], DP_filtered[,"F3"])
length(retain4[retain4==F]) #3875

2. Run poolSeq to obtain short-term Ne values

PWS between 1991 and 2017

methods<-c("W.planI","W.planII","JR.planI","JR.planII","P.planI","P.planII","P.alt.1step.planII")

#calcualte Ne for PWS91-PWS17 period 

pws_filtered<-data.frame(pws_filtered)
DP_filtered<-data.frame(DP_filtered)

pws_Ne<-data.frame(methods=methods)
for (i in 1: length(methods)){
    pws_Ne$Ne[i]<-estimateNe(p0=pws_filtered[,"F0"], pt=pws_filtered[,"F3"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F3"], t=5,
                  method=methods[i], Ncensus=1000,poolSize=c(58,56))
    pws_Ne$Ne_10000[i]<-estimateNe(p0=pws_filtered[,"F0"], pt=pws_filtered[,"F3"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F3"], t=5, method=methods[i], Ncensus=100000,poolSize=c(58,56))
}

write.csv(pws_Ne,"../Output/Ne/Ne_estimation_PWS91-17_angsdAF.csv")
#PlanI requires Ncensus, PlanII does not require Ncensus

#pws_Ne<-read.csv("../Output/Ne/Ne_estimation_PWS91-17_vcfAF.csv", row.names = 1)

library(knitr)
kable(pws_Ne, caption = "Estiamted Ne")

PlanI requires ‘Ncensus’,and PlanII does not require Ncensus. Ncensus =1000 [Ne] and 10000 Ne_10000. Does not make much difference after 10000

3. Estimate Ne for each time point

#further filtered the snp dataset
pws_filtered<-pws_filtered[as.vector(retain3),]
DP_filtered<-DP_filtered[as.vector(retain3),]
retain4<-checkSNP(pws_filtered[,"F2"],pws_filtered[,"F3"],DP_filtered[,"F2"], DP_filtered[,"F3"])
pws_filtered<-pws_filtered[as.vector(retain4),]
DP_filtered<-DP_filtered[as.vector(retain4),]

Ne<-data.frame(methods=methods)
for (i in 1: length(methods)){
    Ne$Ne01_t1[i]<-estimateNe(p0=pws_filtered[,"F0"], pt=pws_filtered[,"F1"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F1"], t=1, method=methods[i], Ncensus=10000,poolSize=c(58,72))
    Ne$Ne12_t2[i]<-estimateNe(p0=pws_filtered[,"F1"], pt=pws_filtered[,"F2"], cov0=DP_filtered[,"F1"], covt=DP_filtered[,"F2"], t=1.8, method=methods[i], Ncensus=10000,poolSize=c(72,46))
    Ne$Ne23_t2[i]<-estimateNe(p0=pws_filtered[,"F2"], pt=pws_filtered[,"F3"], cov0=DP_filtered[,"F2"], covt=DP_filtered[,"F3"], t=1.7, method=methods[i], Ncensus=10000,poolSize=c(46,56))
}

write.csv(Ne, "../Output/Ne/Ne_estimation_PWS_eachTimePeriod_angsdAF.csv")
Ne

4. Plot the results

colnames(Ne)[2:4]<-c("T1","T2","T3")
nem<-reshape2::melt(Ne, id.vars="methods",value.name ="Ne")

ggplot(nem, aes(x=variable, y=Ne, color=methods))+
    geom_point()+
    theme_classic()+ylab("Ne")+xlab("Time period")+
    geom_path(aes(x=variable, y=Ne, group=methods,color=methods))+
    theme(legend.title=element_blank())+ggtitle("PWS")
ggsave("../Output/Ne/Ne_estimates_overtime_PWS.png", width = 6, height = 4, dpi=150)

5. Calculate TB and SS Ne

    1. TB
size<-read.csv("../Data/popinfo/popsize.csv")
pops<-c("TB91","TB96","TB06","TB17")
for (i in 1:length(pops)){
    df<-read.table(paste0("../Data/new_vcf/AF/",pops[i],"_maf05_af.frq"),stringsAsFactors = FALSE,header = FALSE, skip=1, col.names = c("chr","pos","n_allele","n_sample","MajorAF","MAF"))
    df$maf<-substr(df$MAF, 3,10)
    df<-df[,c(1,2,7)]
    df$maf<-as.numeric(df$maf)
    assign(paste0("AF",i),df)
}

#combine AF for all years
AF<-cbind(AF1, AF2[,3],AF3[,3],AF4[,3])
colnames(AF)<-c("chr","pos","F0","F1","F2","F3")
write.csv(AF, "../Output/Ne/TB_maf05_AF.csv")

#Read depth information
for (i in 1:length(pops)){
    df<-read.table(paste0("../Data/new_vcf/depth/",pops[i],"_maf05.depth.info"), header=F)
    colnames(df)<-c("chr","pos","depth")
    assign(paste0("D",i),df)
}
#combine Depth for all years
DP<-cbind(D1, D2[,3],D3[,3],D4[,3])
colnames(DP)<-c("chr","pos","F0","F1","F2","F3")
write.csv(DP,"../Output/Ne/TB_maf05_read_depth.csv")

#Find SNPs with extreme values and uninformative loci and remove them
retain<-checkSNP(AF[,"F0"],AF[,"F3"],DP[,"F0"], DP[,"F3"])
length(retain[retain==F]) #69743
AF_filtered<-AF[retain,]
DP_filtered<-DP[retain,]

#Look at F0 and F1
retain1<-checkSNP(AF_filtered[,"F0"],AF_filtered[,"F1"],DP_filtered[,"F0"], DP_filtered[,"F1"])
length(retain1[retain1==F]) #0

retain2<-checkSNP(AF_filtered[,"F0"],AF_filtered[,"F2"],DP_filtered[,"F0"], DP_filtered[,"F2"])
length(retain2[retain2==F]) #0

retain3<-checkSNP(AF_filtered[,"F1"],AF_filtered[,"F2"],DP_filtered[,"F1"], DP_filtered[,"F2"])
length(retain3[retain3==F]) #22479

retain4<-checkSNP(AF_filtered[,"F2"],AF_filtered[,"F3"],DP_filtered[,"F2"], DP_filtered[,"F3"])
length(retain[retain==F]) 

methods<-c("W.planI","W.planII","JR.planI","JR.planII","P.planI","P.planII","P.alt.1step.planII")

#calcualte Ne for 1991-2017 period 
AF_Ne<-data.frame(methods=methods)
for (i in 1: length(methods)){
    AF_Ne$Ne[i]<-estimateNe(p0=AF_filtered[,"F0"], pt=AF_filtered[,"F3"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F3"], t=5, 
                  method=methods[i], Ncensus=1000,poolSize=c(size$Freq[size$pop==pops[1]],size$Freq[size$pop==pops[4]] ))
    AF_Ne$Ne_10000[i]<-estimateNe(p0=AF_filtered[,"F0"], pt=AF_filtered[,"F3"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F3"], t=5, 
                                   method=methods[i], Ncensus=100000,poolSize= c(size$Freq[size$pop==pops[1]], size$Freq[size$pop==pops[4]]))
    
}
write.csv(AF_Ne,"../Output/Ne/Ne_estimation_TB91-17_vcfAF.csv")

knitr::kable(AF_Ne, caption = "Estiamted Ne of TB")
# Estimate Ne for each time point  
AF_filtered<-AF_filtered[retain3,]
DP_filtered<-DP_filtered[retain3,]
AF_filtered<-AF_filtered[retain4,]
DP_filtered<-DP_filtered[retain4,]

Ne<-data.frame(methods=methods)
for (i in 1: length(methods)){
    Ne$Ne01_t1[i]<-estimateNe(p0=AF_filtered[,"F0"], pt=AF_filtered[,"F1"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F1"], t=1, 
                         method=methods[i], Ncensus=10000,poolSize=c(size$Freq[size$pop==pops[1]],size$Freq[size$pop==pops[2]]))
    Ne$Ne12_t2[i]<-estimateNe(p0=AF_filtered[,"F1"], pt=AF_filtered[,"F2"], cov0=DP_filtered[,"F1"], covt=DP_filtered[,"F2"], t=1.8, 
                              method=methods[i], Ncensus=10000,poolSize=c(size$Freq[size$pop==pops[2]],size$Freq[size$pop==pops[3]]))
    Ne$Ne23_t2[i]<-estimateNe(p0=AF_filtered[,"F2"], pt=AF_filtered[,"F3"], cov0=DP_filtered[,"F2"], covt=DP_filtered[,"F3"], t=1.7, 
                              method=methods[i], Ncensus=10000,poolSize=c(size$Freq[size$pop==pops[3]],size$Freq[size$pop==pops[4]]))
}

write.csv(Ne, "../Output/Ne/Ne_estimation_TB_eachTimePeriod_vcfAF.csv")

colnames(Ne)[2:4]<-c("T1","T2","T3")
nem<-reshape2::melt(Ne, id.vars="methods",value.name ="Ne")

ggplot(nem, aes(x=variable, y=Ne, color=methods))+
    geom_point()+
    theme_classic()+ylab("Ne")+xlab("Time period")+
    geom_path(aes(x=variable, y=Ne, group=methods,color=methods))+
    theme(legend.title=element_blank())+ggtitle("TB")
ggsave("../Output/Ne/Ne_estimates_overtime_TB.png", width = 6, height = 4, dpi=150)

    1. SS
pops<-c("SS96","SS06","SS17")
for (i in 1:length(pops)){
    df<-read.table(paste0("../Data/new_vcf/AF/",pops[i],"_maf05_af.frq"),stringsAsFactors = FALSE,header = FALSE, skip=1, col.names = c("chr","pos","n_allele","n_sample","MajorAF","MAF"))
    df$maf<-substr(df$MAF, 3,10)
    df<-df[,c(1,2,7)]
    df$maf<-as.numeric(df$maf)
    assign(paste0("AF",i),df)
}
#combine AF for all years
AF<-cbind(AF1, AF2[,3],AF3[,3])
colnames(AF)<-c("chr","pos","F0","F1","F2")
write.csv(AF, "../Output/Ne/SS_maf05_AF.csv")

#Read depth information
for (i in 1:length(pops)){
    df<-read.table(paste0("../Data/new_vcf/depth/",pops[i],"_maf05.depth.info"), header=F)
    colnames(df)<-c("chr","pos","depth")
    assign(paste0("D",i),df)
}
#combine Depth for all years
DP<-cbind(D1, D2[,3],D3[,3])
colnames(DP)<-c("chr","pos","F0","F1","F2")
write.csv(DP,"../Output/Ne/SS_maf05_read_depth.csv")

#Find SNPs with extreme values and uninformative loci and remove them
retain<-checkSNP(AF[,"F0"],AF[,"F2"],DP[,"F0"], DP[,"F2"])
length(retain[retain==F]) #10509
AF_filtered<-AF[retain,]
DP_filtered<-DP[retain,]

#Look at F0 and F1
retain1<-checkSNP(AF_filtered[,"F0"],AF_filtered[,"F1"],DP_filtered[,"F0"], DP_filtered[,"F1"])
length(retain1[retain1==F]) #0

retain2<-checkSNP(AF_filtered[,"F0"],AF_filtered[,"F2"],DP_filtered[,"F0"], DP_filtered[,"F2"])
length(retain2[retain2==F]) #0

retain3<-checkSNP(AF_filtered[,"F1"],AF_filtered[,"F2"],DP_filtered[,"F1"], DP_filtered[,"F2"])
length(retain3[retain3==F]) #26551

methods<-c("W.planI","W.planII","JR.planI","JR.planII","P.planI","P.planII","P.alt.1step.planII")
#calcualte Ne for 1991-2017 period 
AF_Ne<-data.frame(methods=methods)
for (i in 1: length(methods)){
    AF_Ne$Ne[i]<-estimateNe(p0=AF_filtered[,"F0"], pt=AF_filtered[,"F2"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F2"], t=5, 
                  method=methods[i], Ncensus=1000,poolSize=c(size$Freq[size$pop==pops[1]],size$Freq[size$pop==pops[3]]))
    AF_Ne$Ne_10000[i]<-estimateNe(p0=AF_filtered[,"F0"], pt=AF_filtered[,"F2"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F2"], t=5, 
                                   method=methods[i], Ncensus=100000,poolSize= c(size$Freq[size$pop==pops[1]],size$Freq[size$pop==pops[3]]))
    
}
write.csv(AF_Ne,"../Output/Ne/Ne_estimation_SS96-17_vcfAF.csv")

knitr::kable(AF_Ne, caption = "Estiamted Ne of SS")
# Estimate Ne for each time point  
AF_filtered<-AF_filtered[retain3,]
DP_filtered<-DP_filtered[retain3,]
Ne<-data.frame(methods=methods)
for (i in 1: length(methods)){
    Ne$Ne01_t1[i]<-estimateNe(p0=AF_filtered[,"F0"], pt=AF_filtered[,"F1"], cov0=DP_filtered[,"F0"], covt=DP_filtered[,"F1"], t=1, 
                         method=methods[i], Ncensus=10000,poolSize=c(size$Freq[size$pop==pops[1]],size$Freq[size$pop==pops[2]]))
    Ne$Ne12_t2[i]<-estimateNe(p0=AF_filtered[,"F1"], pt=AF_filtered[,"F2"], cov0=DP_filtered[,"F1"], covt=DP_filtered[,"F2"], t=1.8, 
                              method=methods[i], Ncensus=10000,poolSize=c(size$Freq[size$pop==pops[2]],size$Freq[size$pop==pops[3]]))
}

write.csv(Ne, "../Output/Ne/Ne_estimation_SS_eachTimePeriod_vcfAF.csv")

colnames(Ne)[2:3]<-c("T1","T2")
nem<-reshape2::melt(Ne, id.vars="methods",value.name ="Ne")

ggplot(nem, aes(x=variable, y=Ne, color=methods))+
    geom_point()+
    theme_classic()+ylab("Ne")+xlab("Time period")+
    geom_path(aes(x=variable, y=Ne, group=methods,color=methods))+
    theme(legend.title=element_blank())+ggtitle("SS")
ggsave("../Output/Ne/Ne_estimates_overtime_SS.png", width = 6, height = 4, dpi=150)

Plot together the P.PlanII results

#Plot together (results from maf0.05 freq files)
library(tibble)
pops<-c("PWS","TB","SS")
Ne<-data.frame()
for (i in 1: length(pops)){
    df<-read.csv(paste0("../Output/Ne/Ne_estimation_",pops[i],"_eachTimePeriod_vcfAF.csv"), row.names = 1)
    df$pop<-pops[i]  
    if (i==3) {
        colnames(df)[2:3]<-c("T2","T3")
        df<-add_column(df, T1=NA, .after=1)
    }
    if (i!=3) colnames(df)[2:4]<-c("T1","T2","T3")
        
    Ne<-rbind(Ne, df[df$methods=="P.planII",])
}

Nem<-reshape2::melt(Ne[,2:5], id.vars="pop")

Nem$pop<-factor(Nem$pop, levels=c("TB","PWS","SS"))
ggplot(Nem, aes(x=variable, y=value, color=pop))+
    geom_point(size=2)+
    theme_classic()+ylab("Ne")+xlab("Time period")+
    geom_path(aes(x=variable, y=value, group=pop,color=pop))+
    theme(legend.title=element_blank())+
    scale_color_manual(values=cols)
ggsave("../Output/Ne/Ne_estimates_overtime_3pops.png", width = 6, height = 4, dpi=150)

Use the Jorde-Ryman temporal method from NeEstimator 2.1.

From https://github.com/pinskylab/codEvol calcNe_ANGSD.r

require(data.table)
require(boot)
source("../Rscripts/calcNe.R")

1. Read the mafs data from ANGSD & trim positions to unlinked loci

Starting with PWS pop

#MAF data
dat91<-fread("../Data/new_vcf/AF/PWS91.mafs.gz")
dat96<-fread("../Data/new_vcf/AF/PWS96.mafs.gz")
dat07<-fread("../Data/new_vcf/AF/PWS07.mafs.gz")
dat17<-fread("../Data/new_vcf/AF/PWS17.mafs.gz")
setkey(dat91, chromo, position)
setkey(dat96, chromo, position)
setkey(dat07, chromo, position)
setkey(dat17, chromo, position)

# unlinked loci from plink
unlnk<-fread('../Data/plink/prune/prune_50.5.0.5.prune.in')
setnames(unlnk, c("chromo","position"))

dat91<-merge(dat91, unlnk)
dat96<-merge(dat96, unlnk)
dat07<-merge(dat07, unlnk)
dat17<-merge(dat17, unlnk)

2. Combine time points and trim loci with freq > 0.1

years<-c("91","96","07","17")
comb<-t(combn(years, 2))

estNe<-data.frame(pop1=comb[,1], pop2=comb[,2])
gens<-c(1,2.67,4.33,1.83,3.5,1.67)

for (i in 5: nrow(comb)){
    df1<-get(paste0("dat",comb[i,1]))
    df2<-get(paste0("dat",comb[i,2]))
    
    setnames(df1, c("knownEM", 'nInd'), c("freq1", 'nInd1'))
    setnames(df2, c("knownEM", 'nInd'), c("freq2", 'nInd2'))
    
    df <- df1[df2, .(chromo, position, freq1, freq2, nInd1, nInd2)][!is.na(freq1) & !is.na(freq2) & freq1 > 0.1 & freq2 > 0.1, ]
    g=gens[i]
    
    estNe$Ne[i]<-df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

    # block bootstrapping across LGs
    uq.ch <- df[, sort(unique(chromo))]

    boot.re <- boot(uq.ch, jrNe2block, 1000, gen = g, alldata = df)
    estNe$median[i]<-median(boot.re$t[is.finite(boot.re$t)]) # median bootstrap
    estNe$mean[i]<-mean(boot.re$t[is.finite(boot.re$t)])
    ci<-boot.ci(boot.re, type = c('perc'))
    #95% C.I.
    estNe$CI.low[i]<-ci$percent[4]
    estNe$CI.up[i]<-ci$percent[5]
    
    #reset the attibutes
    setnames(df1, c("freq1", 'nInd1'),c("knownEM", 'nInd'))
    setnames(df2, c("freq2", 'nInd2'),c("knownEM", 'nInd'))
}

write.csv(estNe,"../Output/Ne/Jorde-Ryman_Ne.estimates_PWS.csv")

#estNe<-read.csv("../Output/Ne/Jorde-Ryman_Ne.estimates_PWS.csv", row.names = 1)
estNe$year<-apply(estNe["pop2"],1, function(x) {if (x=="96") x=1996
                   else if (x=="07") x=2007
                   else if (x=="17") x=2017})

ggplot(estNe[c(1,4,6),], aes(x=year, y=Ne))+
    geom_point(size=2, color="blue")+
    geom_errorbar(aes(ymin = CI.low, ymax = CI.up), width = 0.2, color="blue")+
    geom_path(color="blue")+ylab("Estiamted Ne")+xlab("Year")+
    theme_classic()+ggtitle("PWS")
ggsave("../Output/Ne/Jorde-Ryman_Ne.estimates.png", width = 5, height = 3, dpi=300)
knitr::kable(estNe)

2.2. Combine time points and trim loci with freq > 0.02

  • Lowering the frequency threshold lowers the estimated Ne
years<-c("91","96","07","17")
comb<-t(combn(years, 2))

estNe<-data.frame(pop1=comb[,1], pop2=comb[,2])
gens<-c(1,2.67,4.33,1.83,3.5,1.67)

for (i in 1: nrow(comb)){
    df1<-get(paste0("dat",comb[i,1]))
    df2<-get(paste0("dat",comb[i,2]))
    
    setnames(df1, c("knownEM", 'nInd'), c("freq1", 'nInd1'))
    setnames(df2, c("knownEM", 'nInd'), c("freq2", 'nInd2'))
    
    df <- df1[df2, .(chromo, position, freq1, freq2, nInd1, nInd2)][!is.na(freq1) & !is.na(freq2) & freq1 > 0.02 & freq2 > 0.02, ]
    g=gens[i]
    
    estNe$Ne[i]<-df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

    # block bootstrapping across LGs
    uq.ch <- df[, sort(unique(chromo))]

    boot.re <- boot(uq.ch, jrNe2block, 1000, gen = g, alldata = df)
    estNe$median[i]<-median(boot.re$t[is.finite(boot.re$t)]) # median bootstrap
    estNe$mean[i]<-mean(boot.re$t[is.finite(boot.re$t)])
    ci<-boot.ci(boot.re, type = c('perc'))
    #95% C.I.
    estNe$CI.low[i]<-ci$percent[4]
    estNe$CI.up[i]<-ci$percent[5]
    
    #reset the attibutes
    setnames(df1, c("freq1", 'nInd1'),c("knownEM", 'nInd'))
    setnames(df2, c("freq2", 'nInd2'),c("knownEM", 'nInd'))
}

write.csv(estNe,"../Output/Ne/Jorde-Ryman_Ne.estimates_PWS_0.02threshold.csv")
estNe<-read.csv("../Output/Ne/Jorde-Ryman_Ne.estimates_PWS_0.02threshold.csv", row.names = 1, )
estNe$year<-apply(estNe["pop2"],1, function(x) {if (x=="96") x=1996
                   else if (x=="07"|x=="7") x=2007
                   else if (x=="17") x=2017})

ggplot(estNe[c(1,4,6),], aes(x=year, y=Ne))+
    geom_point(size=2, color="blue")+
    geom_errorbar(aes(ymin = CI.low, ymax = CI.up), width = 0.2, color="blue")+
    geom_path(color="blue")+ylab("Estiamted Ne")+xlab("Year")+
    theme_classic()+ggtitle("PWS")
ggsave("../Output/Ne/Jorde-Ryman_Ne.estimates_0.02Threshold.png", width = 5, height = 3, dpi=300)
  • TB pop
#MAF data
dat91<-fread("../Data/new_vcf/AF/TB91.mafs.gz")
dat96<-fread("../Data/new_vcf/AF/TB96.mafs.gz")
dat06<-fread("../Data/new_vcf/AF/TB06.mafs.gz")
dat17<-fread("../Data/new_vcf/AF/TB17.mafs.gz")
setkey(dat91, chromo, position)
setkey(dat96, chromo, position)
setkey(dat06, chromo, position)
setkey(dat17, chromo, position)

# unlinked loci from plink
unlnk<-fread('../Data/plink/prune/prune_50.5.0.5.prune.in')
setnames(unlnk, c("chromo","position"))

dat91<-merge(dat91, unlnk)
dat96<-merge(dat96, unlnk)
dat06<-merge(dat06, unlnk)
dat17<-merge(dat17, unlnk)

years<-c("91","96","06","17")
comb<-t(combn(years, 2))

estNe<-data.frame(pop1=comb[,1], pop2=comb[,2])
gens<-c(1,2.5,4.33,1.67,3.5,1.83)

for (i in 1: nrow(comb)){
    df1<-get(paste0("dat",comb[i,1]))
    df2<-get(paste0("dat",comb[i,2]))
    
    setnames(df1, c("knownEM", 'nInd'), c("freq1", 'nInd1'))
    setnames(df2, c("knownEM", 'nInd'), c("freq2", 'nInd2'))
    
    df <- df1[df2, .(chromo, position, freq1, freq2, nInd1, nInd2)][!is.na(freq1) & !is.na(freq2) & freq1 > 0.1 & freq2 > 0.1, ]
    g=gens[i]
    
    estNe$Ne[i]<-df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

    # block bootstrapping across LGs
    uq.ch <- df[, sort(unique(chromo))]

    boot.re <- boot(uq.ch, jrNe2block, 1000, gen = g, alldata = df)
    estNe$median[i]<-median(boot.re$t[is.finite(boot.re$t)]) # median bootstrap
    estNe$mean[i]<-mean(boot.re$t[is.finite(boot.re$t)])
    ci<-boot.ci(boot.re, type = c('perc'))
    #95% C.I.
    estNe$CI.low[i]<-ci$percent[4]
    estNe$CI.up[i]<-ci$percent[5]
    
    #reset the attibutes
    setnames(df1, c("freq1", 'nInd1'),c("knownEM", 'nInd'))
    setnames(df2, c("freq2", 'nInd2'),c("knownEM", 'nInd'))
}

write.csv(estNe,"../Output/Ne/Jorde-Ryman_Ne.estimates_TB.csv")

#estNe<-read.csv("../Output/Ne/Jorde-Ryman_Ne.estimates_TB.csv", row.names = 1)
estNe$year<-apply(estNe["pop2"],1, function(x) {if (x=="96") x=1996
                   else if (x=="06") x=2006
                   else if (x=="17") x=2017})

ggplot(estNe[c(1,4,6),], aes(x=year, y=Ne))+
    geom_point(size=2, color="blue")+
    geom_errorbar(aes(ymin = CI.low, ymax = CI.up), width = 0.2, color="blue")+
    geom_path(color="blue")+ylab("Estiamted Ne")+xlab("Year")+
    theme_classic()+ggtitle("TB")
ggsave("../Output/Ne/Jorde-Ryman_Ne.estimates_TB.png", width = 5, height = 3, dpi=300)

  • SS population
#MAF data
dat96<-fread("../Data/new_vcf/AF/SS96.mafs.gz")
dat06<-fread("../Data/new_vcf/AF/SS06.mafs.gz")
dat17<-fread("../Data/new_vcf/AF/SS17.mafs.gz")
setkey(dat96, chromo, position)
setkey(dat06, chromo, position)
setkey(dat17, chromo, position)

# unlinked loci from plink
unlnk<-fread('../Data/plink/prune/prune_50.5.0.5.prune.in')
setnames(unlnk, c("chromo","position"))

dat96<-merge(dat96, unlnk)
dat06<-merge(dat06, unlnk)
dat17<-merge(dat17, unlnk)

years<-c("96","06","17")
comb<-t(combn(years, 2))

estNe<-data.frame(pop1=comb[,1], pop2=comb[,2])
gens<-c(1.67,3.5, 1.83)

for (i in 1: nrow(comb)){
    df1<-get(paste0("dat",comb[i,1]))
    df2<-get(paste0("dat",comb[i,2]))
    
    setnames(df1, c("knownEM", 'nInd'), c("freq1", 'nInd1'))
    setnames(df2, c("knownEM", 'nInd'), c("freq2", 'nInd2'))
    
    df <- df1[df2, .(chromo, position, freq1, freq2, nInd1, nInd2)][!is.na(freq1) & !is.na(freq2) & freq1 > 0.1 & freq2 > 0.1, ]
    g=gens[i]
    
    estNe$Ne[i]<-df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

    # block bootstrapping across LGs
    uq.ch <- df[, sort(unique(chromo))]

    boot.re <- boot(uq.ch, jrNe2block, 1000, gen = g, alldata = df)
    estNe$median[i]<-median(boot.re$t[is.finite(boot.re$t)]) # median bootstrap
    estNe$mean[i]<-mean(boot.re$t[is.finite(boot.re$t)])
    ci<-boot.ci(boot.re, type = c('perc'))
    #95% C.I.
    estNe$CI.low[i]<-ci$percent[4]
    estNe$CI.up[i]<-ci$percent[5]
    
    #reset the attibutes
    setnames(df1, c("freq1", 'nInd1'),c("knownEM", 'nInd'))
    setnames(df2, c("freq2", 'nInd2'),c("knownEM", 'nInd'))
}

write.csv(estNe,"../Output/Ne/Jorde-Ryman_Ne.estimates_SS.csv")

#estNe<-read.csv("../Output/Ne/Jorde-Ryman_Ne.estimates_TB.csv", row.names = 1)
estNe$year<-apply(estNe["pop2"],1, function(x) {if (x=="96") x=1996
                   else if (x=="06") x=2006
                   else if (x=="17") x=2017})

ggplot(estNe[c(1,3),], aes(x=year, y=Ne))+
    geom_point(size=2, color="blue")+
    geom_errorbar(aes(ymin = CI.low, ymax = CI.up), width = 0.2, color="blue")+
    geom_path(color="blue")+ylab("Estiamted Ne")+xlab("Year")+
    theme_classic()+ggtitle("SS")
ggsave("../Output/Ne/Jorde-Ryman_Ne.estimates_SS.png", width = 5, height = 3, dpi=300)

  • Plot 3 populations together

ne<-data.frame()
pops<-c("PWS","TB","SS")
for (i in 1:3){
    df<-read.csv(paste0("../Output/Ne/Jorde-Ryman_Ne.estimates_", pops[i],".csv"), row.names = 1)
    df$pop<-pops[i]
    ne<-rbind(ne, df)
}

ne$year<-apply(ne["pop2"],1, function(x) {if (x=="96") x=1996
                   else if (x==6) x=2006
                   else if (x==7) x=2007
                   else if (x=="17") x=2017})
ne2<-ne[c(1,4,6,7,10,12,13,15),]
ne2$pop<-factor(ne2$pop, levels=c("TB","PWS","SS"))

ggplot(ne2, aes(x=year, y=Ne, color=pop))+
    geom_point(size=2)+
    geom_errorbar(aes(ymin = CI.low, ymax = CI.up), width = 0.2)+
    geom_path()+ylab("Estiamted Ne")+xlab("Year")+
    theme_classic()+
    scale_color_manual(values=cols)

ggsave("../Output/Ne/Jorde-Ryman_Ne.estimates_3Populations.png", width = 5, height = 3, dpi=300)



# Pi null distribution

1. Create persite theta.pest.gz files in angsd


/home/jamcgirr/apps/angsd/misc/thetaStat  print /home/ktist/ph/data/angsd/theta/PWS91_maf00.thetas.idx | gzip > /home/ktist/ph/data/angsd/theta/PWS91_maf00_thetas.pestPG.gz

# Run printTheta.sh at farm

2. run R scripts at farm to create null distribution of genome-wide thetas

Run angsd_theta_siteshuffle_null.sh at farm, which runs Pi_shuffle_pws.R - Takes long time, so create a script for each pop.year combination and run separately

Output from theta shuffling results are in Data/shuffle/theta.siteshuffle.50000.PWS91_PWS96.csv.gz

3. Calculate p-values using the results from shuffling and plot the results

#from codEvol angsd_theta_siteshuffle_null_stats.R

###########################
# load functions
###########################
require(data.table)
require(plyr)
require(ggplot2)
require(RColorBrewer)


#####################
# read in and prep data
#####################

years<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(years, 2))
# max theta per genome from reshuffling (all sites) from angsd_theta_siteshuffle_null.r

chrmax <- fread('../Data/new_vcf/chr_sizes.bed')
chrmax<-chrmax[,-2]
colnames(chrmax)<-c("chr", "len")
chrmax$start<-c(0,cumsum(chrmax$len)[1:(nrow(chrmax)-1)])

chrmax$end<-cumsum(chrmax$len)
chrmax$middle<-(chrmax$end-chrmax$start)/2+chrmax$start

#setkey(chrmax, chr)

#Functions to calculate p-values from codEvol
calcpG <- function(thetachange, null){ # for increases in theta
  return((sum(null > thetachange)+1)/(length(null)+1)) # equation from North et al. 2002 Am J Hum Gen
}
calcpL <- function(thetachange, null){ # for decreases in theta
  return((sum(null < thetachange)+1)/(length(null)+1)) # equation from North et al. 2002 Am J Hum Gen
}


cols <- brewer.pal(4, 'Paired')[rep(1:2,13)]
Datall<-data.table()
for (p in 1: nrow(comb)){
    # max theta per genome from reshuffling (all sites) from angsd_theta_siteshuffle_null.r
    null<-fread(paste0('../Data/shuffle/theta.siteshuffle.50000.', comb[p,1],"_",comb[p,2],'.csv.gz'))
    
    #upper and lower 95%
    null[, .(tWd_l95 = quantile(mintWd, 0.05), tWd_u95 = quantile(maxtWd, probs = 0.95),
                tPd_l95 = quantile(mintPd, 0.05), tPd_u95 = quantile(maxtPd, probs = 0.95),
                tDd_l95 = quantile(mintDd, 0.05), tDd_u95 = quantile(maxtDd, probs = 0.95))]

    #assign(paste0("null.",comb[p,1],"_",comb[p,2]), null)    
    
    # sliding windows theta change (GATK sites) from angsd_theta_siteshuffle_null.r
    dat<-fread(paste0('../Data/shuffle/theta_change_region_50000.', comb[p,1],"_",comb[p,2],'.csv.gz'), drop = 1)
    dat[,pop:=paste0(comb[p,1],"_",comb[p,2])]
    
    dat<-merge(dat, chrmax[,c("chr","start")], by.x="Chromo", by.y = "chr")
    dat[, POSgen := WinCenter + start]
    dat[,start := NULL] #remove start
    
    #calculate p-values
    #1. thetaW loci
    dat[tWd > 0, tWd.p := calcpG(tWd, null$maxtWd), by = .(Chromo, WinCenter)] # thetaW  loci
    dat[tWd <= 0, tWd.p := calcpL(tWd, null$mintWd), by = .(Chromo, WinCenter)]
    #2. theta pi
    dat[tPd > 0, tPd.p := calcpG(tPd, null$maxtPd), by = .(Chromo, WinCenter)] # theta pi
    dat[tPd <= 0, tPd.p := calcpL(tPd, null$mintPd), by = .(Chromo, WinCenter)]
    
    #Tajima's D
    dat[tDd > 0, tDd.p := calcpG(tDd, null$maxtDd), by = .(Chromo, WinCenter)] # tajima's D
    dat[tDd <= 0, tDd.p := calcpL(tDd, null$mintDd), by = .(Chromo, WinCenter)]

    write.csv(dat, file=gzfile(paste0('../Output/Pi/Shuffle/theta_siteshuffle_', comb[p,1],"_",comb[p,2],'.csv.gz')))
    
    Datall<-rbind(Datall, dat)
}

write.csv(Datall, file=gzfile(paste0('../Output/Pi/Shuffle/theta_siteshuffle_PWS_summary.csv.gz')))
   

## Plot the results

#chromosome number locations
winsz = 5e4 

#Changes in Pi between years
Datall$Chromo<-factor(Datall$Chromo, levels=c(paste0("chr",1:26)))
Datall$pop<-factor(Datall$pop, levels=c("PWS91_PWS96","PWS91_PWS07","PWS91_PWS17","PWS96_PWS07","PWS96_PWS17","PWS07_PWS17"))

ggplot(Datall, aes(POSgen, tPd/winsz, color = Chromo)) + 
    geom_point(size = 0.5, alpha = 0.3) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = cols, guide="none") +
    ylab('Change in pi per site')+xlab("Chromosome")+
    ggtitle("Changes in Pi")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave(paste0('../Output/Pi/Shuffle/Changes_in_Pi_PWS.png'), width = 7.5, height = 9, dpi = 300)
    
# plot theta_Waterson change
ggplot(Datall, aes(POSgen, tWd/winsz, color = Chromo)) + 
  geom_point(size = 0.5, alpha = 0.3) +
  scale_color_manual(values = cols, guide="none") +
    facet_wrap(~pop, ncol = 1) +
  ylab('Change in Wattersons theta per site')+xlab("Chromosome")+
  ggtitle("Changes in Pi")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_thetaW_PWS.png', width = 7.5, height = 9, dpi = 300)

# plot Tajima's D change
ggplot(Datall, aes(POSgen, tDd, color = Chromo)) + 
    geom_point(size = 0.5, alpha = 0.3) +
    scale_color_manual(values = cols,guide="none") +
    facet_wrap(~pop, ncol = 1) +
    ylab('Change in Tajimas D per window')+xlab("Chromosome")+
    ggtitle("Changes in Tajima's D")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_TajimasD_PWS.png', width = 7.5, height = 9, dpi = 300)

# plot pi p-value vs. position 
cols <- brewer.pal(4, 'Paired')[rep(1:2,13)]
Datall$Chromo<-factor(Datall$Chromo, levels=c(paste0("chr",1:26)))
Datall$pop<-factor(Datall$pop, levels=c("PWS91_PWS96","PWS91_PWS07","PWS91_PWS17","PWS96_PWS07","PWS96_PWS17","PWS07_PWS17"))

ggplot(Datall, aes(POSgen, -log10(tPd.p)*sign(tPd), color = Chromo)) + 
    geom_point(size = 0.2, alpha = 0.3) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = cols, guide="none") +xlab("Chromosome")+
    ylab("log10(P-value)")+
    geom_hline(yintercept = log10(0.05), linetype = 'dashed', color = 'grey') +
    geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'grey')+
    ggtitle("P-values for changes in Pi")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_Pi.siteshuffle.p-values_PWS.png', width = 7.5, height =11, units = 'in', dpi = 300)


# plot thetaW p-value vs. position (all loci)
ggplot(Datall, aes(POSgen, -log10(tWd.p)*sign(tWd), color = Chromo)) + 
  geom_point(size = 0.2, alpha = 0.3) +
  facet_wrap(~pop, ncol = 1) +
  scale_color_manual(values = cols, guide="none") +xlab("Chromosome")+
    ylab("log10(P-value)")+
  geom_hline(yintercept = log10(0.05), linetype = 'dashed', color = 'grey') +
  geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'grey')+
      ggtitle("P-values for changes in Theta")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_thetaW.siteshuffle.p-values_PWS.png', width = 7.5, height =11, units = 'in', dpi = 300)

#plot Tajama's D p-value vs. position
ggplot(Datall, aes(POSgen, -log10(tDd.p)*sign(tDd), color = Chromo)) + 
    geom_point(size = 0.2, alpha = 0.3) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = cols, guide="none") +xlab("Chromosome")+
    ylab("log10(P-value)")+
    geom_hline(yintercept = log10(0.05), linetype = 'dashed', color = 'grey') +
    geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'grey')+
    ggtitle("P-values for changes in Tajima's D")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_TajimaD.siteshuffle.p-values_PWS.png', width = 7.5, height =11, units = 'in', dpi = 300)

4. Outlier regions

#################
# print outliers
#################

Pi_outliers<-Datall[tPd.p < 0.05,]
Theta_outliers<-Datall[tWd.p < 0.05,]
TajimaD_outliers<-Datall[tDd.p < 0.05,] #no outliers

pi<-data.frame(table(Pi_outliers$pop, Pi_outliers$Chromo))
the<-data.frame(table(Theta_outliers$pop, Theta_outliers$Chromo))
D<-data.frame(table(TajimaD_outliers$pop, TajimaD_outliers$Chromo))

#plot PWS91-96, 96-07, and 07-17
yrs<-c("PWS91_PWS96","PWS96_PWS07","PWS07_PWS17")
col3<-brewer.pal(4,"PuRd")[2:4]

pi2<-pi[pi$Var1 %in% yrs,]
pi2$Var1<-factor(pi2$Var1, levels=yrs)
ggplot(pi2, aes(x=Var2, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=col3)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(expression(paste("Changes in ", pi)))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Pi_significant_perChrom_perPop.png", width = 8, height = 4, dpi=300) 

th2<-the[the$Var1 %in% yrs,]
th2$Var1<-factor(th2$Var1, levels=yrs)
ggplot(th2, aes(x=Var2, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=col3)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(paste0("Changes in theta"))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Theta_significant_perChrom_perPop.png", width = 8, height = 4, dpi=300) 

D2<-D[D$Var1 %in% yrs,]
D2$Var1<-factor(D2$Var1, levels=yrs)
ggplot(D2, aes(x=Var2, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=col3)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
     ggtitle(paste0("Changes in Tajima's D"))+
    xlab('')+ylab('Number of regions with P>0.05')
ggsave("../Output/Pi/Shuffle/Pi_significant_perChrom_perPop.png", width = 8, height = 4, dpi=300) 


sum<-data.frame(table(Pi_outliers$pop))
sum2<-data.frame(table(Theta_outliers$pop))
#sum3<-data.frame(table(TajimaD_outliers$pop)) no outliers

sum<-cbind(sum, sum2$Freq)
colnames(sum)<-c("Pops", "Pi", "Theta")
knitr::kable(t(sum))
  • Most differences exist between 1996 and 2007
  • Chr25 has the most significant regions for changes in Pi and Theta s
LS0tCnRpdGxlOiAiRXN0aW1hdGVOZSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICAgIHRvYzogdHJ1ZSAKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgICAgdGhlbWU6IGx1bWVuCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMgRXN0aW1hdGUgZWZmZWN0aXZlIHBvcHVsYXRpb24gc2l6ZSAoTmUpIG9mIFBXUyBmcm9tIGFsbGVsZSBmcmVxdW5jeSBjaGFnbmVzIAogCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNvdXJjZSgiLi4vUnNjcmlwdHMvQmFzZVNjcmlwdHMuUiIpCnJlcXVpcmUoZGF0YS50YWJsZSkKcmVxdWlyZShwbHlyKQpyZXF1aXJlKFJDb2xvckJyZXdlcikKbGlicmFyeShwb29sU2VxKQpsaWJyYXJ5KGRhdGEudGFibGUpCmBgYAoKIyMgTmVzdC9Qb29sU2VxIHBhY2thZ2UgaXMgdXNlZC4gClJlZjogZG9pOiAxMC4xNTM0L2dlbmV0aWNzLjExNi4xOTExOTcKCgoxLiBTdWJzZXQgVkNGIGZpbGVzIGJ5IHBvcHVsYXRpb24gIApgYGB7YmFzaH0KI3N1YnNldCBhIFZDRiBmaWxlIGJ5IHBvcHVsYXRpb24gKHN1YnNldF92Y2ZfYnlQb3BQV1Muc2gpCgojIS9iaW4vYmFzaAojU0JBVENIIC0tam9iLW5hbWU9c3Vic2V0UG9wCiNTQkFUQ0ggLS1tZW09MTZHIAojU0JBVENIIC0tbm9kZXM9NCAKI1NCQVRDSCAtLW50YXNrcz04IAojU0JBVENIIC1lIHN1YnNldFBvcC5lcnIgIAojU0JBVENIIC0tdGltZT03MjowMDowMCAgCiNTQkFUQ0ggLS1tYWlsLXVzZXI9a3Rpc3RAdWNkYXZpcy5lZHUgIyNlbWFpbCB5b3Ugd2hlbiBqb2Igc3RhcnRzLGVuZHMsZXRjCiNTQkFUQ0ggLS1tYWlsLXR5cGU9QUxMCgojU0JBVENIIC1wIGhpZ2ggIAoKbW9kdWxlIGxvYWQgYmNmdG9vbHMKCmJjZnRvb2xzIHZpZXcgLU96IC1TIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9QV1MwNy50eHQgLS10aHJlYWRzIDE2IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vUFdTb25seTA3X21hZjA1LnZjZi5neiAKYmNmdG9vbHMgdmlldyAtT3ogLVMgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL1BXUzE3LnR4dCAtLXRocmVhZHMgMTYgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X05TMC41X21hZjA1LnZjZi5neiA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9QV1Nvbmx5MTdfbWFmMDUudmNmLmd6IApiY2Z0b29scyB2aWV3IC1PeiAtUyAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vUFdTOTEudHh0IC0tdGhyZWFkcyAxNiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfTlMwLjVfbWFmMDUudmNmLmd6ID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL1BXU29ubHk5MV9tYWYwNS52Y2YuZ3ogCmJjZnRvb2xzIHZpZXcgLU96IC1TIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9QV1M5Ni50eHQgLS10aHJlYWRzIDE2IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vUFdTb25seTk2X21hZjA1LnZjZi5neiAKCmBgYAoKMi4gQ2FsY3VsYXRlIGFsbGVsZSBmcmVxdWVuY3kgdXNpbmcgQU5HU0QgIApgYGB7YmFzaH0KI0NhbGN1bGF0ZSBhbGxlbGUgZnJlcXVlbmN5IHVzaW5nIFZDRnRvb2xzIChjYWxjdWxhdGVBRl9WQ0Z0b29scy5zaCkKCiMhL2Jpbi9iYXNoIC1sCiNTQkFUQ0ggLS1qb2ItbmFtZT1jYWxjQUYKI1NCQVRDSCAtLW1lbT0xNkcKI1NCQVRDSCAtLW5vZGVzPTQgCiNTQkFUQ0ggLS1udGFza3M9OCAKI1NCQVRDSCAtLWVycm9yIGNhbGNBRi5lcnIKI1NCQVRDSCAtLXRpbWU9NDg6MDA6MDAKI1NCQVRDSCAtLW1haWwtdXNlcj1rdGlzdEB1Y2RhdmlzLmVkdSAjI2VtYWlsIHlvdSB3aGVuIGpvYiBzdGFydHMsZW5kcyxldGMKI1NCQVRDSCAtLW1haWwtdHlwZT1BTEwKI1NCQVRDSCAtcCBoaWdoIAoKbW9kdWxlIGxvYWQgYW5nc2QKCmFuZ3NkIC1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9hbmdzZC9BRi9QV1M5MSAtZmFpIC9ob21lL2phbWNnaXJyL3BoL2RhdGEvY19oYXJlbmd1cy9jLmhhcmVuZ3VzLmZhLmZhaSAtZG9HbGYgMiAtZG9NYWYgMyAtZG9NYWpvck1pbm9yIDQgLWRvUG9zdCAxIC1kb0dlbm8gMiAtdmNmLXBsIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9QV1M5MV9tYWYwNS52Y2YuZ3ogLXJlZiAvaG9tZS9qYW1jZ2lyci9waC9kYXRhL2NfaGFyZW5ndXMvYy5oYXJlbmd1cy5mYSAKCgpgYGAKCjMuIE9idGFpbiByZWFkIGRlcHRocyBmcm9tIFZDRiBmaWxlcyAgCmBgYHtiYXNofQojT2J0YWluIGRlcHRoIGluZm9ybWF0aW9uIGZyb20gVkNGIGZpbGVzIChleHRyYWN0X2NvdmVyYWdlUFdTLnNoKQoKIyEvYmluL2Jhc2gKI1NCQVRDSCAtLWpvYi1uYW1lPWV4dHJhY3RfY292ZXJhZ2UgCiNTQkFUQ0ggLS1tZW09MTZHIAojU0JBVENIIC0tbnRhc2tzPTEgCiNTQkFUQ0ggLWUgZXh0cmFjdF9jb3ZlcmFnZS5lcnIgIAojU0JBVENIIC0tdGltZT00ODowMDowMCAgCiNTQkFUQ0ggLS1tYWlsLXVzZXI9a3Rpc3RAdWNkYXZpcy5lZHUgIyNlbWFpbCB5b3Ugd2hlbiBqb2Igc3RhcnRzLGVuZHMsZXRjCiNTQkFUQ0ggLS1tYWlsLXR5cGU9QUxMCiNTQkFUQ0ggLXAgaGlnaCAgCgptb2R1bGUgbG9hZCBiY2Z0b29scwpiY2Z0b29scyBxdWVyeSAtZiAnJUNIUk9NICAlUE9TICAlSU5GTy9EUFxuJyAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vUFdTMDdfbWFmMDUudmNmLmd6ID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9kZXB0aC9QV1MwN19tYWYwNS5kZXB0aC5pbmZvIAoKYGBgCgojIyBVc2UgcG9vbFNlcSB0byBjYWxjdWFsdGUgTmUgCgojIyMgMS4gUmVhZCBBRiAoZnJxKSBmaWxlcyBhbmQgZmlsdGVyIG91dCBleHRyZW1lIHZhbHVlcyBhbmQgdW5pbmZvcm1hdGl2ZSBsb2NpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcG9wczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQp5cjwtYyg5MSw5NiwiMDciLDE3KQoKI1JlYWQgdGhlIGFsbGVsZSBmcmVxIGRhdGEgZm9yIFBXUyBhbmQgdHJpbSBmb3IgdW5saW5rZWQgbG9jaQp1bmxuazwtZnJlYWQoJy4uL0RhdGEvcGxpbmsvcHJ1bmUvcHJ1bmVfNTAuNS4wLjUucHJ1bmUuaW4nKQpzZXRuYW1lcyh1bmxuaywgYygiY2hyb21vIiwicG9zaXRpb24iKSkKc2V0a2V5KHVubG5rLCBjaHJvbW8sIHBvc2l0aW9uKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LWZyZWFkKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL0FGLyIscG9wc1tpXSwiLm1hZnMuZ3oiKSkKICAgIGRmPC1kZlssYygxLDIsNildCiAgICBzZXRrZXkoZGYsIGNocm9tbywgcG9zaXRpb24pCiAgICBkZjwtbWVyZ2UoZGYsIHVubG5rKQogICAgYXNzaWduKHBhc3RlMCgicHdzIixpKSxkZikKfQoKCiNjb21iaW5lIEFGIGZvciBhbGwgeWVhcnMKcHdzPC1jYmluZChwd3MxLCBwd3MyWywzXSxwd3MzWywzXSxwd3M0WywzXSkKY29sbmFtZXMocHdzKTwtYygiY2hyIiwicG9zIiwiRjAiLCJGMSIsIkYyIiwiRjMiKQojd3JpdGUuY3N2KHB3cywgIi4uL091dHB1dC9OZS9QV1Nvbmx5X0FGLmNzdiIpCgojUmVhZCBkZXB0aCBpbmZvcm1hdGlvbgpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LWZyZWFkKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2RlcHRoLyIscG9wc1tpXSwiX21hZjA1LmRlcHRoLmluZm8iKSkKICAgIHNldG5hbWVzKGRmLCBjKCJjaHJvbW8iLCJwb3NpdGlvbiIsImRlcHRoIikpCiAgICBzZXRrZXkoZGYsY2hyb21vLHBvc2l0aW9uKQogICAgZGY8LW1lcmdlKGRmLCB1bmxuaykKICAgIGFzc2lnbihwYXN0ZTAoIkQiLGkpLGRmKQp9CiNjb21iaW5lIERlcHRoIGZvciBhbGwgeWVhcnMKRFA8LWNiaW5kKEQxLCBEMlssM10sRDNbLDNdLEQ0WywzXSkKY29sbmFtZXMoRFApPC1jKCJjaHIiLCJwb3MiLCJGMCIsIkYxIiwiRjIiLCJGMyIpCiN3cml0ZS5jc3YoRFAsIi4uL091dHB1dC9OZS9QV1Nvbmx5X3JlYWRfZGVwdGguY3N2IikKCiNGaW5kIFNOUHMgd2l0aCBleHRyZW1lIHZhbHVlcyBhbmQgdW5pbmZvcm1hdGl2ZSBsb2NpIGFuZCByZW1vdmUgdGhlbQpyZXRhaW48LWNoZWNrU05QKHB3c1ssIkYwIl0scHdzWywiRjMiXSxEUFssIkYwIl0sIERQWywiRjMiXSkKbGVuZ3RoKHJldGFpbltyZXRhaW49PUZdKSAjMTE4MCB3aWxsIGJlIHJlbW92ZWQKCiNmaWx0ZXJlZCB0aGUgc25wIGRhdGFzZXQKcHdzX2ZpbHRlcmVkPC1wd3NbYXMudmVjdG9yKHJldGFpbiksXQpEUF9maWx0ZXJlZDwtRFBbYXMudmVjdG9yKHJldGFpbiksXQoKI0xvb2sgYXQgRjAgYW5kIEYxCnJldGFpbjE8LWNoZWNrU05QKHB3c19maWx0ZXJlZFssIkYwIl0scHdzX2ZpbHRlcmVkWywiRjEiXSxEUF9maWx0ZXJlZFssIkYwIl0sIERQX2ZpbHRlcmVkWywiRjEiXSkKbGVuZ3RoKHJldGFpbjFbcmV0YWluMT09Rl0pICMwCgpyZXRhaW4yPC1jaGVja1NOUChwd3NfZmlsdGVyZWRbLCJGMCJdLHB3c19maWx0ZXJlZFssIkYyIl0sRFBfZmlsdGVyZWRbLCJGMCJdLCBEUF9maWx0ZXJlZFssIkYyIl0pCmxlbmd0aChyZXRhaW4yW3JldGFpbjI9PUZdKSAjMAoKcmV0YWluMzwtY2hlY2tTTlAocHdzX2ZpbHRlcmVkWywiRjEiXSxwd3NfZmlsdGVyZWRbLCJGMiJdLERQX2ZpbHRlcmVkWywiRjEiXSwgRFBfZmlsdGVyZWRbLCJGMiJdKQpsZW5ndGgocmV0YWluM1tyZXRhaW4zPT1GXSkgIzgzMQoKcmV0YWluNDwtY2hlY2tTTlAocHdzX2ZpbHRlcmVkWywiRjIiXSxwd3NfZmlsdGVyZWRbLCJGMyJdLERQX2ZpbHRlcmVkWywiRjIiXSwgRFBfZmlsdGVyZWRbLCJGMyJdKQpsZW5ndGgocmV0YWluNFtyZXRhaW40PT1GXSkgIzM4NzUKCmBgYAoKIyMjIDIuIFJ1biBwb29sU2VxIHRvIG9idGFpbiBzaG9ydC10ZXJtIE5lIHZhbHVlcyAKUFdTIGJldHdlZW4gMTk5MSBhbmQgMjAxNyAgCmBgYHtSfQptZXRob2RzPC1jKCJXLnBsYW5JIiwiVy5wbGFuSUkiLCJKUi5wbGFuSSIsIkpSLnBsYW5JSSIsIlAucGxhbkkiLCJQLnBsYW5JSSIsIlAuYWx0LjFzdGVwLnBsYW5JSSIpCgojY2FsY3VhbHRlIE5lIGZvciBQV1M5MS1QV1MxNyBwZXJpb2QgCgpwd3NfZmlsdGVyZWQ8LWRhdGEuZnJhbWUocHdzX2ZpbHRlcmVkKQpEUF9maWx0ZXJlZDwtZGF0YS5mcmFtZShEUF9maWx0ZXJlZCkKCnB3c19OZTwtZGF0YS5mcmFtZShtZXRob2RzPW1ldGhvZHMpCmZvciAoaSBpbiAxOiBsZW5ndGgobWV0aG9kcykpewogICAgcHdzX05lJE5lW2ldPC1lc3RpbWF0ZU5lKHAwPXB3c19maWx0ZXJlZFssIkYwIl0sIHB0PXB3c19maWx0ZXJlZFssIkYzIl0sIGNvdjA9RFBfZmlsdGVyZWRbLCJGMCJdLCBjb3Z0PURQX2ZpbHRlcmVkWywiRjMiXSwgdD01LAogICAgICAgICAgICAgICAgICBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwLHBvb2xTaXplPWMoNTgsNTYpKQogICAgcHdzX05lJE5lXzEwMDAwW2ldPC1lc3RpbWF0ZU5lKHAwPXB3c19maWx0ZXJlZFssIkYwIl0sIHB0PXB3c19maWx0ZXJlZFssIkYzIl0sIGNvdjA9RFBfZmlsdGVyZWRbLCJGMCJdLCBjb3Z0PURQX2ZpbHRlcmVkWywiRjMiXSwgdD01LCBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwMDAscG9vbFNpemU9Yyg1OCw1NikpCn0KCndyaXRlLmNzdihwd3NfTmUsIi4uL091dHB1dC9OZS9OZV9lc3RpbWF0aW9uX1BXUzkxLTE3X2FuZ3NkQUYuY3N2IikKI1BsYW5JIHJlcXVpcmVzIE5jZW5zdXMsIFBsYW5JSSBkb2VzIG5vdCByZXF1aXJlIE5jZW5zdXMKCiNwd3NfTmU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGlvbl9QV1M5MS0xN192Y2ZBRi5jc3YiLCByb3cubmFtZXMgPSAxKQoKbGlicmFyeShrbml0cikKa2FibGUocHdzX05lLCBjYXB0aW9uID0gIkVzdGlhbXRlZCBOZSIpCgpgYGAKClBsYW5JIHJlcXVpcmVzICdOY2Vuc3VzJyxhbmQgUGxhbklJIGRvZXMgbm90IHJlcXVpcmUgTmNlbnN1cy4gTmNlbnN1cyA9MTAwMCBbTmVdIGFuZCAxMDAwMCBOZV8xMDAwMC4KRG9lcyBub3QgbWFrZSBtdWNoIGRpZmZlcmVuY2UgYWZ0ZXIgMTAwMDAKCiMjIyAzLiBFc3RpbWF0ZSBOZSBmb3IgZWFjaCB0aW1lIHBvaW50ICAKYGBge3J9CiNmdXJ0aGVyIGZpbHRlcmVkIHRoZSBzbnAgZGF0YXNldApwd3NfZmlsdGVyZWQ8LXB3c19maWx0ZXJlZFthcy52ZWN0b3IocmV0YWluMyksXQpEUF9maWx0ZXJlZDwtRFBfZmlsdGVyZWRbYXMudmVjdG9yKHJldGFpbjMpLF0KcmV0YWluNDwtY2hlY2tTTlAocHdzX2ZpbHRlcmVkWywiRjIiXSxwd3NfZmlsdGVyZWRbLCJGMyJdLERQX2ZpbHRlcmVkWywiRjIiXSwgRFBfZmlsdGVyZWRbLCJGMyJdKQpwd3NfZmlsdGVyZWQ8LXB3c19maWx0ZXJlZFthcy52ZWN0b3IocmV0YWluNCksXQpEUF9maWx0ZXJlZDwtRFBfZmlsdGVyZWRbYXMudmVjdG9yKHJldGFpbjQpLF0KCk5lPC1kYXRhLmZyYW1lKG1ldGhvZHM9bWV0aG9kcykKZm9yIChpIGluIDE6IGxlbmd0aChtZXRob2RzKSl7CiAgICBOZSROZTAxX3QxW2ldPC1lc3RpbWF0ZU5lKHAwPXB3c19maWx0ZXJlZFssIkYwIl0sIHB0PXB3c19maWx0ZXJlZFssIkYxIl0sIGNvdjA9RFBfZmlsdGVyZWRbLCJGMCJdLCBjb3Z0PURQX2ZpbHRlcmVkWywiRjEiXSwgdD0xLCBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwMCxwb29sU2l6ZT1jKDU4LDcyKSkKICAgIE5lJE5lMTJfdDJbaV08LWVzdGltYXRlTmUocDA9cHdzX2ZpbHRlcmVkWywiRjEiXSwgcHQ9cHdzX2ZpbHRlcmVkWywiRjIiXSwgY292MD1EUF9maWx0ZXJlZFssIkYxIl0sIGNvdnQ9RFBfZmlsdGVyZWRbLCJGMiJdLCB0PTEuOCwgbWV0aG9kPW1ldGhvZHNbaV0sIE5jZW5zdXM9MTAwMDAscG9vbFNpemU9Yyg3Miw0NikpCiAgICBOZSROZTIzX3QyW2ldPC1lc3RpbWF0ZU5lKHAwPXB3c19maWx0ZXJlZFssIkYyIl0sIHB0PXB3c19maWx0ZXJlZFssIkYzIl0sIGNvdjA9RFBfZmlsdGVyZWRbLCJGMiJdLCBjb3Z0PURQX2ZpbHRlcmVkWywiRjMiXSwgdD0xLjcsIG1ldGhvZD1tZXRob2RzW2ldLCBOY2Vuc3VzPTEwMDAwLHBvb2xTaXplPWMoNDYsNTYpKQp9Cgp3cml0ZS5jc3YoTmUsICIuLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGlvbl9QV1NfZWFjaFRpbWVQZXJpb2RfYW5nc2RBRi5jc3YiKQpOZQoKYGBgCgoKIyMjIDQuIFBsb3QgdGhlIHJlc3VsdHMKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY29sbmFtZXMoTmUpWzI6NF08LWMoIlQxIiwiVDIiLCJUMyIpCm5lbTwtcmVzaGFwZTI6Om1lbHQoTmUsIGlkLnZhcnM9Im1ldGhvZHMiLHZhbHVlLm5hbWUgPSJOZSIpCgpnZ3Bsb3QobmVtLCBhZXMoeD12YXJpYWJsZSwgeT1OZSwgY29sb3I9bWV0aG9kcykpKwogICAgZ2VvbV9wb2ludCgpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIk5lIikreGxhYigiVGltZSBwZXJpb2QiKSsKICAgIGdlb21fcGF0aChhZXMoeD12YXJpYWJsZSwgeT1OZSwgZ3JvdXA9bWV0aG9kcyxjb2xvcj1tZXRob2RzKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKStnZ3RpdGxlKCJQV1MiKQpnZ3NhdmUoIi4uL091dHB1dC9OZS9OZV9lc3RpbWF0ZXNfb3ZlcnRpbWVfUFdTLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGVzX292ZXJ0aW1lX1BXUy5wbmcpICAKCiMjIyA1LiBDYWxjdWxhdGUgVEIgYW5kIFNTIE5lICAKCi0gMS4gVEIKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2l6ZTwtcmVhZC5jc3YoIi4uL0RhdGEvcG9waW5mby9wb3BzaXplLmNzdiIpCnBvcHM8LWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvQUYvIixwb3BzW2ldLCJfbWFmMDVfYWYuZnJxIiksc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLGhlYWRlciA9IEZBTFNFLCBza2lwPTEsIGNvbC5uYW1lcyA9IGMoImNociIsInBvcyIsIm5fYWxsZWxlIiwibl9zYW1wbGUiLCJNYWpvckFGIiwiTUFGIikpCiAgICBkZiRtYWY8LXN1YnN0cihkZiRNQUYsIDMsMTApCiAgICBkZjwtZGZbLGMoMSwyLDcpXQogICAgZGYkbWFmPC1hcy5udW1lcmljKGRmJG1hZikKICAgIGFzc2lnbihwYXN0ZTAoIkFGIixpKSxkZikKfQoKI2NvbWJpbmUgQUYgZm9yIGFsbCB5ZWFycwpBRjwtY2JpbmQoQUYxLCBBRjJbLDNdLEFGM1ssM10sQUY0WywzXSkKY29sbmFtZXMoQUYpPC1jKCJjaHIiLCJwb3MiLCJGMCIsIkYxIiwiRjIiLCJGMyIpCndyaXRlLmNzdihBRiwgIi4uL091dHB1dC9OZS9UQl9tYWYwNV9BRi5jc3YiKQoKI1JlYWQgZGVwdGggaW5mb3JtYXRpb24KZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2RlcHRoLyIscG9wc1tpXSwiX21hZjA1LmRlcHRoLmluZm8iKSwgaGVhZGVyPUYpCiAgICBjb2xuYW1lcyhkZik8LWMoImNociIsInBvcyIsImRlcHRoIikKICAgIGFzc2lnbihwYXN0ZTAoIkQiLGkpLGRmKQp9CiNjb21iaW5lIERlcHRoIGZvciBhbGwgeWVhcnMKRFA8LWNiaW5kKEQxLCBEMlssM10sRDNbLDNdLEQ0WywzXSkKY29sbmFtZXMoRFApPC1jKCJjaHIiLCJwb3MiLCJGMCIsIkYxIiwiRjIiLCJGMyIpCndyaXRlLmNzdihEUCwiLi4vT3V0cHV0L05lL1RCX21hZjA1X3JlYWRfZGVwdGguY3N2IikKCiNGaW5kIFNOUHMgd2l0aCBleHRyZW1lIHZhbHVlcyBhbmQgdW5pbmZvcm1hdGl2ZSBsb2NpIGFuZCByZW1vdmUgdGhlbQpyZXRhaW48LWNoZWNrU05QKEFGWywiRjAiXSxBRlssIkYzIl0sRFBbLCJGMCJdLCBEUFssIkYzIl0pCmxlbmd0aChyZXRhaW5bcmV0YWluPT1GXSkgIzY5NzQzCkFGX2ZpbHRlcmVkPC1BRltyZXRhaW4sXQpEUF9maWx0ZXJlZDwtRFBbcmV0YWluLF0KCiNMb29rIGF0IEYwIGFuZCBGMQpyZXRhaW4xPC1jaGVja1NOUChBRl9maWx0ZXJlZFssIkYwIl0sQUZfZmlsdGVyZWRbLCJGMSJdLERQX2ZpbHRlcmVkWywiRjAiXSwgRFBfZmlsdGVyZWRbLCJGMSJdKQpsZW5ndGgocmV0YWluMVtyZXRhaW4xPT1GXSkgIzAKCnJldGFpbjI8LWNoZWNrU05QKEFGX2ZpbHRlcmVkWywiRjAiXSxBRl9maWx0ZXJlZFssIkYyIl0sRFBfZmlsdGVyZWRbLCJGMCJdLCBEUF9maWx0ZXJlZFssIkYyIl0pCmxlbmd0aChyZXRhaW4yW3JldGFpbjI9PUZdKSAjMAoKcmV0YWluMzwtY2hlY2tTTlAoQUZfZmlsdGVyZWRbLCJGMSJdLEFGX2ZpbHRlcmVkWywiRjIiXSxEUF9maWx0ZXJlZFssIkYxIl0sIERQX2ZpbHRlcmVkWywiRjIiXSkKbGVuZ3RoKHJldGFpbjNbcmV0YWluMz09Rl0pICMyMjQ3OQoKcmV0YWluNDwtY2hlY2tTTlAoQUZfZmlsdGVyZWRbLCJGMiJdLEFGX2ZpbHRlcmVkWywiRjMiXSxEUF9maWx0ZXJlZFssIkYyIl0sIERQX2ZpbHRlcmVkWywiRjMiXSkKbGVuZ3RoKHJldGFpbltyZXRhaW49PUZdKSAKCm1ldGhvZHM8LWMoIlcucGxhbkkiLCJXLnBsYW5JSSIsIkpSLnBsYW5JIiwiSlIucGxhbklJIiwiUC5wbGFuSSIsIlAucGxhbklJIiwiUC5hbHQuMXN0ZXAucGxhbklJIikKCiNjYWxjdWFsdGUgTmUgZm9yIDE5OTEtMjAxNyBwZXJpb2QgCkFGX05lPC1kYXRhLmZyYW1lKG1ldGhvZHM9bWV0aG9kcykKZm9yIChpIGluIDE6IGxlbmd0aChtZXRob2RzKSl7CiAgICBBRl9OZSROZVtpXTwtZXN0aW1hdGVOZShwMD1BRl9maWx0ZXJlZFssIkYwIl0sIHB0PUFGX2ZpbHRlcmVkWywiRjMiXSwgY292MD1EUF9maWx0ZXJlZFssIkYwIl0sIGNvdnQ9RFBfZmlsdGVyZWRbLCJGMyJdLCB0PTUsIAogICAgICAgICAgICAgICAgICBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwLHBvb2xTaXplPWMoc2l6ZSRGcmVxW3NpemUkcG9wPT1wb3BzWzFdXSxzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbNF1dICkpCiAgICBBRl9OZSROZV8xMDAwMFtpXTwtZXN0aW1hdGVOZShwMD1BRl9maWx0ZXJlZFssIkYwIl0sIHB0PUFGX2ZpbHRlcmVkWywiRjMiXSwgY292MD1EUF9maWx0ZXJlZFssIkYwIl0sIGNvdnQ9RFBfZmlsdGVyZWRbLCJGMyJdLCB0PTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD1tZXRob2RzW2ldLCBOY2Vuc3VzPTEwMDAwMCxwb29sU2l6ZT0gYyhzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbMV1dLCBzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbNF1dKSkKICAgIAp9CndyaXRlLmNzdihBRl9OZSwiLi4vT3V0cHV0L05lL05lX2VzdGltYXRpb25fVEI5MS0xN192Y2ZBRi5jc3YiKQoKa25pdHI6OmthYmxlKEFGX05lLCBjYXB0aW9uID0gIkVzdGlhbXRlZCBOZSBvZiBUQiIpCgpgYGAKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIEVzdGltYXRlIE5lIGZvciBlYWNoIHRpbWUgcG9pbnQgIApBRl9maWx0ZXJlZDwtQUZfZmlsdGVyZWRbcmV0YWluMyxdCkRQX2ZpbHRlcmVkPC1EUF9maWx0ZXJlZFtyZXRhaW4zLF0KQUZfZmlsdGVyZWQ8LUFGX2ZpbHRlcmVkW3JldGFpbjQsXQpEUF9maWx0ZXJlZDwtRFBfZmlsdGVyZWRbcmV0YWluNCxdCgpOZTwtZGF0YS5mcmFtZShtZXRob2RzPW1ldGhvZHMpCmZvciAoaSBpbiAxOiBsZW5ndGgobWV0aG9kcykpewogICAgTmUkTmUwMV90MVtpXTwtZXN0aW1hdGVOZShwMD1BRl9maWx0ZXJlZFssIkYwIl0sIHB0PUFGX2ZpbHRlcmVkWywiRjEiXSwgY292MD1EUF9maWx0ZXJlZFssIkYwIl0sIGNvdnQ9RFBfZmlsdGVyZWRbLCJGMSJdLCB0PTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPW1ldGhvZHNbaV0sIE5jZW5zdXM9MTAwMDAscG9vbFNpemU9YyhzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbMV1dLHNpemUkRnJlcVtzaXplJHBvcD09cG9wc1syXV0pKQogICAgTmUkTmUxMl90MltpXTwtZXN0aW1hdGVOZShwMD1BRl9maWx0ZXJlZFssIkYxIl0sIHB0PUFGX2ZpbHRlcmVkWywiRjIiXSwgY292MD1EUF9maWx0ZXJlZFssIkYxIl0sIGNvdnQ9RFBfZmlsdGVyZWRbLCJGMiJdLCB0PTEuOCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD1tZXRob2RzW2ldLCBOY2Vuc3VzPTEwMDAwLHBvb2xTaXplPWMoc2l6ZSRGcmVxW3NpemUkcG9wPT1wb3BzWzJdXSxzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbM11dKSkKICAgIE5lJE5lMjNfdDJbaV08LWVzdGltYXRlTmUocDA9QUZfZmlsdGVyZWRbLCJGMiJdLCBwdD1BRl9maWx0ZXJlZFssIkYzIl0sIGNvdjA9RFBfZmlsdGVyZWRbLCJGMiJdLCBjb3Z0PURQX2ZpbHRlcmVkWywiRjMiXSwgdD0xLjcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwMCxwb29sU2l6ZT1jKHNpemUkRnJlcVtzaXplJHBvcD09cG9wc1szXV0sc2l6ZSRGcmVxW3NpemUkcG9wPT1wb3BzWzRdXSkpCn0KCndyaXRlLmNzdihOZSwgIi4uL091dHB1dC9OZS9OZV9lc3RpbWF0aW9uX1RCX2VhY2hUaW1lUGVyaW9kX3ZjZkFGLmNzdiIpCgpjb2xuYW1lcyhOZSlbMjo0XTwtYygiVDEiLCJUMiIsIlQzIikKbmVtPC1yZXNoYXBlMjo6bWVsdChOZSwgaWQudmFycz0ibWV0aG9kcyIsdmFsdWUubmFtZSA9Ik5lIikKCmdncGxvdChuZW0sIGFlcyh4PXZhcmlhYmxlLCB5PU5lLCBjb2xvcj1tZXRob2RzKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICB0aGVtZV9jbGFzc2ljKCkreWxhYigiTmUiKSt4bGFiKCJUaW1lIHBlcmlvZCIpKwogICAgZ2VvbV9wYXRoKGFlcyh4PXZhcmlhYmxlLCB5PU5lLCBncm91cD1tZXRob2RzLGNvbG9yPW1ldGhvZHMpKSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpK2dndGl0bGUoIlRCIikKZ2dzYXZlKCIuLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGVzX292ZXJ0aW1lX1RCLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGVzX292ZXJ0aW1lX1RCLnBuZykKCi0gMi4gU1MgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wczwtYygiU1M5NiIsIlNTMDYiLCJTUzE3IikKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL0FGLyIscG9wc1tpXSwiX21hZjA1X2FmLmZycSIpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSxoZWFkZXIgPSBGQUxTRSwgc2tpcD0xLCBjb2wubmFtZXMgPSBjKCJjaHIiLCJwb3MiLCJuX2FsbGVsZSIsIm5fc2FtcGxlIiwiTWFqb3JBRiIsIk1BRiIpKQogICAgZGYkbWFmPC1zdWJzdHIoZGYkTUFGLCAzLDEwKQogICAgZGY8LWRmWyxjKDEsMiw3KV0KICAgIGRmJG1hZjwtYXMubnVtZXJpYyhkZiRtYWYpCiAgICBhc3NpZ24ocGFzdGUwKCJBRiIsaSksZGYpCn0KI2NvbWJpbmUgQUYgZm9yIGFsbCB5ZWFycwpBRjwtY2JpbmQoQUYxLCBBRjJbLDNdLEFGM1ssM10pCmNvbG5hbWVzKEFGKTwtYygiY2hyIiwicG9zIiwiRjAiLCJGMSIsIkYyIikKd3JpdGUuY3N2KEFGLCAiLi4vT3V0cHV0L05lL1NTX21hZjA1X0FGLmNzdiIpCgojUmVhZCBkZXB0aCBpbmZvcm1hdGlvbgpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvZGVwdGgvIixwb3BzW2ldLCJfbWFmMDUuZGVwdGguaW5mbyIpLCBoZWFkZXI9RikKICAgIGNvbG5hbWVzKGRmKTwtYygiY2hyIiwicG9zIiwiZGVwdGgiKQogICAgYXNzaWduKHBhc3RlMCgiRCIsaSksZGYpCn0KI2NvbWJpbmUgRGVwdGggZm9yIGFsbCB5ZWFycwpEUDwtY2JpbmQoRDEsIEQyWywzXSxEM1ssM10pCmNvbG5hbWVzKERQKTwtYygiY2hyIiwicG9zIiwiRjAiLCJGMSIsIkYyIikKd3JpdGUuY3N2KERQLCIuLi9PdXRwdXQvTmUvU1NfbWFmMDVfcmVhZF9kZXB0aC5jc3YiKQoKI0ZpbmQgU05QcyB3aXRoIGV4dHJlbWUgdmFsdWVzIGFuZCB1bmluZm9ybWF0aXZlIGxvY2kgYW5kIHJlbW92ZSB0aGVtCnJldGFpbjwtY2hlY2tTTlAoQUZbLCJGMCJdLEFGWywiRjIiXSxEUFssIkYwIl0sIERQWywiRjIiXSkKbGVuZ3RoKHJldGFpbltyZXRhaW49PUZdKSAjMTA1MDkKQUZfZmlsdGVyZWQ8LUFGW3JldGFpbixdCkRQX2ZpbHRlcmVkPC1EUFtyZXRhaW4sXQoKI0xvb2sgYXQgRjAgYW5kIEYxCnJldGFpbjE8LWNoZWNrU05QKEFGX2ZpbHRlcmVkWywiRjAiXSxBRl9maWx0ZXJlZFssIkYxIl0sRFBfZmlsdGVyZWRbLCJGMCJdLCBEUF9maWx0ZXJlZFssIkYxIl0pCmxlbmd0aChyZXRhaW4xW3JldGFpbjE9PUZdKSAjMAoKcmV0YWluMjwtY2hlY2tTTlAoQUZfZmlsdGVyZWRbLCJGMCJdLEFGX2ZpbHRlcmVkWywiRjIiXSxEUF9maWx0ZXJlZFssIkYwIl0sIERQX2ZpbHRlcmVkWywiRjIiXSkKbGVuZ3RoKHJldGFpbjJbcmV0YWluMj09Rl0pICMwCgpyZXRhaW4zPC1jaGVja1NOUChBRl9maWx0ZXJlZFssIkYxIl0sQUZfZmlsdGVyZWRbLCJGMiJdLERQX2ZpbHRlcmVkWywiRjEiXSwgRFBfZmlsdGVyZWRbLCJGMiJdKQpsZW5ndGgocmV0YWluM1tyZXRhaW4zPT1GXSkgIzI2NTUxCgptZXRob2RzPC1jKCJXLnBsYW5JIiwiVy5wbGFuSUkiLCJKUi5wbGFuSSIsIkpSLnBsYW5JSSIsIlAucGxhbkkiLCJQLnBsYW5JSSIsIlAuYWx0LjFzdGVwLnBsYW5JSSIpCiNjYWxjdWFsdGUgTmUgZm9yIDE5OTEtMjAxNyBwZXJpb2QgCkFGX05lPC1kYXRhLmZyYW1lKG1ldGhvZHM9bWV0aG9kcykKZm9yIChpIGluIDE6IGxlbmd0aChtZXRob2RzKSl7CiAgICBBRl9OZSROZVtpXTwtZXN0aW1hdGVOZShwMD1BRl9maWx0ZXJlZFssIkYwIl0sIHB0PUFGX2ZpbHRlcmVkWywiRjIiXSwgY292MD1EUF9maWx0ZXJlZFssIkYwIl0sIGNvdnQ9RFBfZmlsdGVyZWRbLCJGMiJdLCB0PTUsIAogICAgICAgICAgICAgICAgICBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwLHBvb2xTaXplPWMoc2l6ZSRGcmVxW3NpemUkcG9wPT1wb3BzWzFdXSxzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbM11dKSkKICAgIEFGX05lJE5lXzEwMDAwW2ldPC1lc3RpbWF0ZU5lKHAwPUFGX2ZpbHRlcmVkWywiRjAiXSwgcHQ9QUZfZmlsdGVyZWRbLCJGMiJdLCBjb3YwPURQX2ZpbHRlcmVkWywiRjAiXSwgY292dD1EUF9maWx0ZXJlZFssIkYyIl0sIHQ9NSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPW1ldGhvZHNbaV0sIE5jZW5zdXM9MTAwMDAwLHBvb2xTaXplPSBjKHNpemUkRnJlcVtzaXplJHBvcD09cG9wc1sxXV0sc2l6ZSRGcmVxW3NpemUkcG9wPT1wb3BzWzNdXSkpCiAgICAKfQp3cml0ZS5jc3YoQUZfTmUsIi4uL091dHB1dC9OZS9OZV9lc3RpbWF0aW9uX1NTOTYtMTdfdmNmQUYuY3N2IikKCmtuaXRyOjprYWJsZShBRl9OZSwgY2FwdGlvbiA9ICJFc3RpYW10ZWQgTmUgb2YgU1MiKQoKYGBgCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBFc3RpbWF0ZSBOZSBmb3IgZWFjaCB0aW1lIHBvaW50ICAKQUZfZmlsdGVyZWQ8LUFGX2ZpbHRlcmVkW3JldGFpbjMsXQpEUF9maWx0ZXJlZDwtRFBfZmlsdGVyZWRbcmV0YWluMyxdCk5lPC1kYXRhLmZyYW1lKG1ldGhvZHM9bWV0aG9kcykKZm9yIChpIGluIDE6IGxlbmd0aChtZXRob2RzKSl7CiAgICBOZSROZTAxX3QxW2ldPC1lc3RpbWF0ZU5lKHAwPUFGX2ZpbHRlcmVkWywiRjAiXSwgcHQ9QUZfZmlsdGVyZWRbLCJGMSJdLCBjb3YwPURQX2ZpbHRlcmVkWywiRjAiXSwgY292dD1EUF9maWx0ZXJlZFssIkYxIl0sIHQ9MSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9bWV0aG9kc1tpXSwgTmNlbnN1cz0xMDAwMCxwb29sU2l6ZT1jKHNpemUkRnJlcVtzaXplJHBvcD09cG9wc1sxXV0sc2l6ZSRGcmVxW3NpemUkcG9wPT1wb3BzWzJdXSkpCiAgICBOZSROZTEyX3QyW2ldPC1lc3RpbWF0ZU5lKHAwPUFGX2ZpbHRlcmVkWywiRjEiXSwgcHQ9QUZfZmlsdGVyZWRbLCJGMiJdLCBjb3YwPURQX2ZpbHRlcmVkWywiRjEiXSwgY292dD1EUF9maWx0ZXJlZFssIkYyIl0sIHQ9MS44LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPW1ldGhvZHNbaV0sIE5jZW5zdXM9MTAwMDAscG9vbFNpemU9YyhzaXplJEZyZXFbc2l6ZSRwb3A9PXBvcHNbMl1dLHNpemUkRnJlcVtzaXplJHBvcD09cG9wc1szXV0pKQp9Cgp3cml0ZS5jc3YoTmUsICIuLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGlvbl9TU19lYWNoVGltZVBlcmlvZF92Y2ZBRi5jc3YiKQoKY29sbmFtZXMoTmUpWzI6M108LWMoIlQxIiwiVDIiKQpuZW08LXJlc2hhcGUyOjptZWx0KE5lLCBpZC52YXJzPSJtZXRob2RzIix2YWx1ZS5uYW1lID0iTmUiKQoKZ2dwbG90KG5lbSwgYWVzKHg9dmFyaWFibGUsIHk9TmUsIGNvbG9yPW1ldGhvZHMpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIHRoZW1lX2NsYXNzaWMoKSt5bGFiKCJOZSIpK3hsYWIoIlRpbWUgcGVyaW9kIikrCiAgICBnZW9tX3BhdGgoYWVzKHg9dmFyaWFibGUsIHk9TmUsIGdyb3VwPW1ldGhvZHMsY29sb3I9bWV0aG9kcykpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkrZ2d0aXRsZSgiU1MiKQpnZ3NhdmUoIi4uL091dHB1dC9OZS9OZV9lc3RpbWF0ZXNfb3ZlcnRpbWVfU1MucG5nIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGk9MTUwKQpgYGAKIVtdKC4uL091dHB1dC9OZS9OZV9lc3RpbWF0ZXNfb3ZlcnRpbWVfU1MucG5nKQoKIyMjIFBsb3QgdG9nZXRoZXIgdGhlIFAuUGxhbklJIHJlc3VsdHMKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI1Bsb3QgdG9nZXRoZXIgKHJlc3VsdHMgZnJvbSBtYWYwLjA1IGZyZXEgZmlsZXMpCmxpYnJhcnkodGliYmxlKQpwb3BzPC1jKCJQV1MiLCJUQiIsIlNTIikKTmU8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbGVuZ3RoKHBvcHMpKXsKICAgIGRmPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9OZS9OZV9lc3RpbWF0aW9uXyIscG9wc1tpXSwiX2VhY2hUaW1lUGVyaW9kX3ZjZkFGLmNzdiIpLCByb3cubmFtZXMgPSAxKQogICAgZGYkcG9wPC1wb3BzW2ldICAKICAgIGlmIChpPT0zKSB7CiAgICAgICAgY29sbmFtZXMoZGYpWzI6M108LWMoIlQyIiwiVDMiKQogICAgICAgIGRmPC1hZGRfY29sdW1uKGRmLCBUMT1OQSwgLmFmdGVyPTEpCiAgICB9CiAgICBpZiAoaSE9MykgY29sbmFtZXMoZGYpWzI6NF08LWMoIlQxIiwiVDIiLCJUMyIpCiAgICAgICAgCiAgICBOZTwtcmJpbmQoTmUsIGRmW2RmJG1ldGhvZHM9PSJQLnBsYW5JSSIsXSkKfQoKTmVtPC1yZXNoYXBlMjo6bWVsdChOZVssMjo1XSwgaWQudmFycz0icG9wIikKCk5lbSRwb3A8LWZhY3RvcihOZW0kcG9wLCBsZXZlbHM9YygiVEIiLCJQV1MiLCJTUyIpKQpnZ3Bsb3QoTmVtLCBhZXMoeD12YXJpYWJsZSwgeT12YWx1ZSwgY29sb3I9cG9wKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MikrCiAgICB0aGVtZV9jbGFzc2ljKCkreWxhYigiTmUiKSt4bGFiKCJUaW1lIHBlcmlvZCIpKwogICAgZ2VvbV9wYXRoKGFlcyh4PXZhcmlhYmxlLCB5PXZhbHVlLCBncm91cD1wb3AsY29sb3I9cG9wKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29scykKZ2dzYXZlKCIuLi9PdXRwdXQvTmUvTmVfZXN0aW1hdGVzX292ZXJ0aW1lXzNwb3BzLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKYGBgCgohW10oLi4vT3V0cHV0L05lL05lX2VzdGltYXRlc19vdmVydGltZV8zcG9wcy5wbmcpCgoKCiMjIFVzZSB0aGUgSm9yZGUtUnltYW4gdGVtcG9yYWwgbWV0aG9kIGZyb20gTmVFc3RpbWF0b3IgMi4xLgoKRnJvbSBodHRwczovL2dpdGh1Yi5jb20vcGluc2t5bGFiL2NvZEV2b2wgY2FsY05lX0FOR1NELnIgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUoYm9vdCkKc291cmNlKCIuLi9Sc2NyaXB0cy9jYWxjTmUuUiIpCmBgYAoKIyMjIDEuIFJlYWQgdGhlIG1hZnMgZGF0YSBmcm9tIEFOR1NEICYgdHJpbSBwb3NpdGlvbnMgdG8gdW5saW5rZWQgbG9jaQpTdGFydGluZyB3aXRoIFBXUyBwb3AgIApgYGB7ciBldmFsPUZBTFNFfQojTUFGIGRhdGEKZGF0OTE8LWZyZWFkKCIuLi9EYXRhL25ld192Y2YvQUYvUFdTOTEubWFmcy5neiIpCmRhdDk2PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1BXUzk2Lm1hZnMuZ3oiKQpkYXQwNzwtZnJlYWQoIi4uL0RhdGEvbmV3X3ZjZi9BRi9QV1MwNy5tYWZzLmd6IikKZGF0MTc8LWZyZWFkKCIuLi9EYXRhL25ld192Y2YvQUYvUFdTMTcubWFmcy5neiIpCnNldGtleShkYXQ5MSwgY2hyb21vLCBwb3NpdGlvbikKc2V0a2V5KGRhdDk2LCBjaHJvbW8sIHBvc2l0aW9uKQpzZXRrZXkoZGF0MDcsIGNocm9tbywgcG9zaXRpb24pCnNldGtleShkYXQxNywgY2hyb21vLCBwb3NpdGlvbikKCiMgdW5saW5rZWQgbG9jaSBmcm9tIHBsaW5rCnVubG5rPC1mcmVhZCgnLi4vRGF0YS9wbGluay9wcnVuZS9wcnVuZV81MC41LjAuNS5wcnVuZS5pbicpCnNldG5hbWVzKHVubG5rLCBjKCJjaHJvbW8iLCJwb3NpdGlvbiIpKQoKZGF0OTE8LW1lcmdlKGRhdDkxLCB1bmxuaykKZGF0OTY8LW1lcmdlKGRhdDk2LCB1bmxuaykKZGF0MDc8LW1lcmdlKGRhdDA3LCB1bmxuaykKZGF0MTc8LW1lcmdlKGRhdDE3LCB1bmxuaykKCmBgYAoKIyMjIDIuIENvbWJpbmUgdGltZSBwb2ludHMgYW5kIHRyaW0gbG9jaSB3aXRoIGZyZXEgPiAwLjEgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KeWVhcnM8LWMoIjkxIiwiOTYiLCIwNyIsIjE3IikKY29tYjwtdChjb21ibih5ZWFycywgMikpCgplc3ROZTwtZGF0YS5mcmFtZShwb3AxPWNvbWJbLDFdLCBwb3AyPWNvbWJbLDJdKQpnZW5zPC1jKDEsMi42Nyw0LjMzLDEuODMsMy41LDEuNjcpCgpmb3IgKGkgaW4gNTogbnJvdyhjb21iKSl7CiAgICBkZjE8LWdldChwYXN0ZTAoImRhdCIsY29tYltpLDFdKSkKICAgIGRmMjwtZ2V0KHBhc3RlMCgiZGF0Iixjb21iW2ksMl0pKQogICAgCiAgICBzZXRuYW1lcyhkZjEsIGMoImtub3duRU0iLCAnbkluZCcpLCBjKCJmcmVxMSIsICduSW5kMScpKQogICAgc2V0bmFtZXMoZGYyLCBjKCJrbm93bkVNIiwgJ25JbmQnKSwgYygiZnJlcTIiLCAnbkluZDInKSkKICAgIAogICAgZGYgPC0gZGYxW2RmMiwgLihjaHJvbW8sIHBvc2l0aW9uLCBmcmVxMSwgZnJlcTIsIG5JbmQxLCBuSW5kMildWyFpcy5uYShmcmVxMSkgJiAhaXMubmEoZnJlcTIpICYgZnJlcTEgPiAwLjEgJiBmcmVxMiA+IDAuMSwgXQogICAgZz1nZW5zW2ldCiAgICAKICAgIGVzdE5lJE5lW2ldPC1kZlssIGpyTmUyKGZyZXExLCBmcmVxMiwgbkluZDEsIG5JbmQyLCBnKV0gCgogICAgIyBibG9jayBib290c3RyYXBwaW5nIGFjcm9zcyBMR3MKICAgIHVxLmNoIDwtIGRmWywgc29ydCh1bmlxdWUoY2hyb21vKSldCgogICAgYm9vdC5yZSA8LSBib290KHVxLmNoLCBqck5lMmJsb2NrLCAxMDAwLCBnZW4gPSBnLCBhbGxkYXRhID0gZGYpCiAgICBlc3ROZSRtZWRpYW5baV08LW1lZGlhbihib290LnJlJHRbaXMuZmluaXRlKGJvb3QucmUkdCldKSAjIG1lZGlhbiBib290c3RyYXAKICAgIGVzdE5lJG1lYW5baV08LW1lYW4oYm9vdC5yZSR0W2lzLmZpbml0ZShib290LnJlJHQpXSkKICAgIGNpPC1ib290LmNpKGJvb3QucmUsIHR5cGUgPSBjKCdwZXJjJykpCiAgICAjOTUlIEMuSS4KICAgIGVzdE5lJENJLmxvd1tpXTwtY2kkcGVyY2VudFs0XQogICAgZXN0TmUkQ0kudXBbaV08LWNpJHBlcmNlbnRbNV0KICAgIAogICAgI3Jlc2V0IHRoZSBhdHRpYnV0ZXMKICAgIHNldG5hbWVzKGRmMSwgYygiZnJlcTEiLCAnbkluZDEnKSxjKCJrbm93bkVNIiwgJ25JbmQnKSkKICAgIHNldG5hbWVzKGRmMiwgYygiZnJlcTIiLCAnbkluZDInKSxjKCJrbm93bkVNIiwgJ25JbmQnKSkKfQoKd3JpdGUuY3N2KGVzdE5lLCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzX1BXUy5jc3YiKQoKI2VzdE5lPC1yZWFkLmNzdigiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc19QV1MuY3N2Iiwgcm93Lm5hbWVzID0gMSkKZXN0TmUkeWVhcjwtYXBwbHkoZXN0TmVbInBvcDIiXSwxLCBmdW5jdGlvbih4KSB7aWYgKHg9PSI5NiIpIHg9MTk5NgogICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoeD09IjA3IikgeD0yMDA3CiAgICAgICAgICAgICAgICAgICBlbHNlIGlmICh4PT0iMTciKSB4PTIwMTd9KQoKZ2dwbG90KGVzdE5lW2MoMSw0LDYpLF0sIGFlcyh4PXllYXIsIHk9TmUpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0yLCBjb2xvcj0iYmx1ZSIpKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IENJLmxvdywgeW1heCA9IENJLnVwKSwgd2lkdGggPSAwLjIsIGNvbG9yPSJibHVlIikrCiAgICBnZW9tX3BhdGgoY29sb3I9ImJsdWUiKSt5bGFiKCJFc3RpYW10ZWQgTmUiKSt4bGFiKCJZZWFyIikrCiAgICB0aGVtZV9jbGFzc2ljKCkrZ2d0aXRsZSgiUFdTIikKZ2dzYXZlKCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMywgZHBpPTMwMCkKCgpgYGAKCmBgYHtyfQprbml0cjo6a2FibGUoZXN0TmUpCmBgYAoKCiFbXSguLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzLnBuZyl7d2lkdGg9NjAlfQoKIyMjIDIuMi4gQ29tYmluZSB0aW1lIHBvaW50cyBhbmQgdHJpbSBsb2NpIHdpdGggZnJlcSA+IDAuMDIgICAKKiBMb3dlcmluZyB0aGUgZnJlcXVlbmN5IHRocmVzaG9sZCBsb3dlcnMgdGhlIGVzdGltYXRlZCBOZSAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnllYXJzPC1jKCI5MSIsIjk2IiwiMDciLCIxNyIpCmNvbWI8LXQoY29tYm4oeWVhcnMsIDIpKQoKZXN0TmU8LWRhdGEuZnJhbWUocG9wMT1jb21iWywxXSwgcG9wMj1jb21iWywyXSkKZ2VuczwtYygxLDIuNjcsNC4zMywxLjgzLDMuNSwxLjY3KQoKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgZGYxPC1nZXQocGFzdGUwKCJkYXQiLGNvbWJbaSwxXSkpCiAgICBkZjI8LWdldChwYXN0ZTAoImRhdCIsY29tYltpLDJdKSkKICAgIAogICAgc2V0bmFtZXMoZGYxLCBjKCJrbm93bkVNIiwgJ25JbmQnKSwgYygiZnJlcTEiLCAnbkluZDEnKSkKICAgIHNldG5hbWVzKGRmMiwgYygia25vd25FTSIsICduSW5kJyksIGMoImZyZXEyIiwgJ25JbmQyJykpCiAgICAKICAgIGRmIDwtIGRmMVtkZjIsIC4oY2hyb21vLCBwb3NpdGlvbiwgZnJlcTEsIGZyZXEyLCBuSW5kMSwgbkluZDIpXVshaXMubmEoZnJlcTEpICYgIWlzLm5hKGZyZXEyKSAmIGZyZXExID4gMC4wMiAmIGZyZXEyID4gMC4wMiwgXQogICAgZz1nZW5zW2ldCiAgICAKICAgIGVzdE5lJE5lW2ldPC1kZlssIGpyTmUyKGZyZXExLCBmcmVxMiwgbkluZDEsIG5JbmQyLCBnKV0gCgogICAgIyBibG9jayBib290c3RyYXBwaW5nIGFjcm9zcyBMR3MKICAgIHVxLmNoIDwtIGRmWywgc29ydCh1bmlxdWUoY2hyb21vKSldCgogICAgYm9vdC5yZSA8LSBib290KHVxLmNoLCBqck5lMmJsb2NrLCAxMDAwLCBnZW4gPSBnLCBhbGxkYXRhID0gZGYpCiAgICBlc3ROZSRtZWRpYW5baV08LW1lZGlhbihib290LnJlJHRbaXMuZmluaXRlKGJvb3QucmUkdCldKSAjIG1lZGlhbiBib290c3RyYXAKICAgIGVzdE5lJG1lYW5baV08LW1lYW4oYm9vdC5yZSR0W2lzLmZpbml0ZShib290LnJlJHQpXSkKICAgIGNpPC1ib290LmNpKGJvb3QucmUsIHR5cGUgPSBjKCdwZXJjJykpCiAgICAjOTUlIEMuSS4KICAgIGVzdE5lJENJLmxvd1tpXTwtY2kkcGVyY2VudFs0XQogICAgZXN0TmUkQ0kudXBbaV08LWNpJHBlcmNlbnRbNV0KICAgIAogICAgI3Jlc2V0IHRoZSBhdHRpYnV0ZXMKICAgIHNldG5hbWVzKGRmMSwgYygiZnJlcTEiLCAnbkluZDEnKSxjKCJrbm93bkVNIiwgJ25JbmQnKSkKICAgIHNldG5hbWVzKGRmMiwgYygiZnJlcTIiLCAnbkluZDInKSxjKCJrbm93bkVNIiwgJ25JbmQnKSkKfQoKd3JpdGUuY3N2KGVzdE5lLCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzX1BXU18wLjAydGhyZXNob2xkLmNzdiIpCmVzdE5lPC1yZWFkLmNzdigiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc19QV1NfMC4wMnRocmVzaG9sZC5jc3YiLCByb3cubmFtZXMgPSAxLCApCmVzdE5lJHllYXI8LWFwcGx5KGVzdE5lWyJwb3AyIl0sMSwgZnVuY3Rpb24oeCkge2lmICh4PT0iOTYiKSB4PTE5OTYKICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHg9PSIwNyJ8eD09IjciKSB4PTIwMDcKICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHg9PSIxNyIpIHg9MjAxN30pCgpnZ3Bsb3QoZXN0TmVbYygxLDQsNiksXSwgYWVzKHg9eWVhciwgeT1OZSkpKwogICAgZ2VvbV9wb2ludChzaXplPTIsIGNvbG9yPSJibHVlIikrCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gQ0kubG93LCB5bWF4ID0gQ0kudXApLCB3aWR0aCA9IDAuMiwgY29sb3I9ImJsdWUiKSsKICAgIGdlb21fcGF0aChjb2xvcj0iYmx1ZSIpK3lsYWIoIkVzdGlhbXRlZCBOZSIpK3hsYWIoIlllYXIiKSsKICAgIHRoZW1lX2NsYXNzaWMoKStnZ3RpdGxlKCJQV1MiKQpnZ3NhdmUoIi4uL091dHB1dC9OZS9Kb3JkZS1SeW1hbl9OZS5lc3RpbWF0ZXNfMC4wMlRocmVzaG9sZC5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIGRwaT0zMDApCmBgYAoKCgoKKiBUQiBwb3AgIAoKYGBge3IgZXZhbD1GQUxTRX0KI01BRiBkYXRhCmRhdDkxPC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1RCOTEubWFmcy5neiIpCmRhdDk2PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1RCOTYubWFmcy5neiIpCmRhdDA2PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1RCMDYubWFmcy5neiIpCmRhdDE3PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1RCMTcubWFmcy5neiIpCnNldGtleShkYXQ5MSwgY2hyb21vLCBwb3NpdGlvbikKc2V0a2V5KGRhdDk2LCBjaHJvbW8sIHBvc2l0aW9uKQpzZXRrZXkoZGF0MDYsIGNocm9tbywgcG9zaXRpb24pCnNldGtleShkYXQxNywgY2hyb21vLCBwb3NpdGlvbikKCiMgdW5saW5rZWQgbG9jaSBmcm9tIHBsaW5rCnVubG5rPC1mcmVhZCgnLi4vRGF0YS9wbGluay9wcnVuZS9wcnVuZV81MC41LjAuNS5wcnVuZS5pbicpCnNldG5hbWVzKHVubG5rLCBjKCJjaHJvbW8iLCJwb3NpdGlvbiIpKQoKZGF0OTE8LW1lcmdlKGRhdDkxLCB1bmxuaykKZGF0OTY8LW1lcmdlKGRhdDk2LCB1bmxuaykKZGF0MDY8LW1lcmdlKGRhdDA2LCB1bmxuaykKZGF0MTc8LW1lcmdlKGRhdDE3LCB1bmxuaykKCnllYXJzPC1jKCI5MSIsIjk2IiwiMDYiLCIxNyIpCmNvbWI8LXQoY29tYm4oeWVhcnMsIDIpKQoKZXN0TmU8LWRhdGEuZnJhbWUocG9wMT1jb21iWywxXSwgcG9wMj1jb21iWywyXSkKZ2VuczwtYygxLDIuNSw0LjMzLDEuNjcsMy41LDEuODMpCgpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBkZjE8LWdldChwYXN0ZTAoImRhdCIsY29tYltpLDFdKSkKICAgIGRmMjwtZ2V0KHBhc3RlMCgiZGF0Iixjb21iW2ksMl0pKQogICAgCiAgICBzZXRuYW1lcyhkZjEsIGMoImtub3duRU0iLCAnbkluZCcpLCBjKCJmcmVxMSIsICduSW5kMScpKQogICAgc2V0bmFtZXMoZGYyLCBjKCJrbm93bkVNIiwgJ25JbmQnKSwgYygiZnJlcTIiLCAnbkluZDInKSkKICAgIAogICAgZGYgPC0gZGYxW2RmMiwgLihjaHJvbW8sIHBvc2l0aW9uLCBmcmVxMSwgZnJlcTIsIG5JbmQxLCBuSW5kMildWyFpcy5uYShmcmVxMSkgJiAhaXMubmEoZnJlcTIpICYgZnJlcTEgPiAwLjEgJiBmcmVxMiA+IDAuMSwgXQogICAgZz1nZW5zW2ldCiAgICAKICAgIGVzdE5lJE5lW2ldPC1kZlssIGpyTmUyKGZyZXExLCBmcmVxMiwgbkluZDEsIG5JbmQyLCBnKV0gCgogICAgIyBibG9jayBib290c3RyYXBwaW5nIGFjcm9zcyBMR3MKICAgIHVxLmNoIDwtIGRmWywgc29ydCh1bmlxdWUoY2hyb21vKSldCgogICAgYm9vdC5yZSA8LSBib290KHVxLmNoLCBqck5lMmJsb2NrLCAxMDAwLCBnZW4gPSBnLCBhbGxkYXRhID0gZGYpCiAgICBlc3ROZSRtZWRpYW5baV08LW1lZGlhbihib290LnJlJHRbaXMuZmluaXRlKGJvb3QucmUkdCldKSAjIG1lZGlhbiBib290c3RyYXAKICAgIGVzdE5lJG1lYW5baV08LW1lYW4oYm9vdC5yZSR0W2lzLmZpbml0ZShib290LnJlJHQpXSkKICAgIGNpPC1ib290LmNpKGJvb3QucmUsIHR5cGUgPSBjKCdwZXJjJykpCiAgICAjOTUlIEMuSS4KICAgIGVzdE5lJENJLmxvd1tpXTwtY2kkcGVyY2VudFs0XQogICAgZXN0TmUkQ0kudXBbaV08LWNpJHBlcmNlbnRbNV0KICAgIAogICAgI3Jlc2V0IHRoZSBhdHRpYnV0ZXMKICAgIHNldG5hbWVzKGRmMSwgYygiZnJlcTEiLCAnbkluZDEnKSxjKCJrbm93bkVNIiwgJ25JbmQnKSkKICAgIHNldG5hbWVzKGRmMiwgYygiZnJlcTIiLCAnbkluZDInKSxjKCJrbm93bkVNIiwgJ25JbmQnKSkKfQoKd3JpdGUuY3N2KGVzdE5lLCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzX1RCLmNzdiIpCgojZXN0TmU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzX1RCLmNzdiIsIHJvdy5uYW1lcyA9IDEpCmVzdE5lJHllYXI8LWFwcGx5KGVzdE5lWyJwb3AyIl0sMSwgZnVuY3Rpb24oeCkge2lmICh4PT0iOTYiKSB4PTE5OTYKICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHg9PSIwNiIpIHg9MjAwNgogICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoeD09IjE3IikgeD0yMDE3fSkKCmdncGxvdChlc3ROZVtjKDEsNCw2KSxdLCBhZXMoeD15ZWFyLCB5PU5lKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MiwgY29sb3I9ImJsdWUiKSsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBDSS5sb3csIHltYXggPSBDSS51cCksIHdpZHRoID0gMC4yLCBjb2xvcj0iYmx1ZSIpKwogICAgZ2VvbV9wYXRoKGNvbG9yPSJibHVlIikreWxhYigiRXN0aWFtdGVkIE5lIikreGxhYigiWWVhciIpKwogICAgdGhlbWVfY2xhc3NpYygpK2dndGl0bGUoIlRCIikKZ2dzYXZlKCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzX1RCLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMywgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc19UQi5wbmcpICAKCgoqIFNTIHBvcHVsYXRpb24KYGBge3IgZXZhbD1GQUxTRX0KI01BRiBkYXRhCmRhdDk2PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1NTOTYubWFmcy5neiIpCmRhdDA2PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1NTMDYubWFmcy5neiIpCmRhdDE3PC1mcmVhZCgiLi4vRGF0YS9uZXdfdmNmL0FGL1NTMTcubWFmcy5neiIpCnNldGtleShkYXQ5NiwgY2hyb21vLCBwb3NpdGlvbikKc2V0a2V5KGRhdDA2LCBjaHJvbW8sIHBvc2l0aW9uKQpzZXRrZXkoZGF0MTcsIGNocm9tbywgcG9zaXRpb24pCgojIHVubGlua2VkIGxvY2kgZnJvbSBwbGluawp1bmxuazwtZnJlYWQoJy4uL0RhdGEvcGxpbmsvcHJ1bmUvcHJ1bmVfNTAuNS4wLjUucHJ1bmUuaW4nKQpzZXRuYW1lcyh1bmxuaywgYygiY2hyb21vIiwicG9zaXRpb24iKSkKCmRhdDk2PC1tZXJnZShkYXQ5NiwgdW5sbmspCmRhdDA2PC1tZXJnZShkYXQwNiwgdW5sbmspCmRhdDE3PC1tZXJnZShkYXQxNywgdW5sbmspCgp5ZWFyczwtYygiOTYiLCIwNiIsIjE3IikKY29tYjwtdChjb21ibih5ZWFycywgMikpCgplc3ROZTwtZGF0YS5mcmFtZShwb3AxPWNvbWJbLDFdLCBwb3AyPWNvbWJbLDJdKQpnZW5zPC1jKDEuNjcsMy41LCAxLjgzKQoKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgZGYxPC1nZXQocGFzdGUwKCJkYXQiLGNvbWJbaSwxXSkpCiAgICBkZjI8LWdldChwYXN0ZTAoImRhdCIsY29tYltpLDJdKSkKICAgIAogICAgc2V0bmFtZXMoZGYxLCBjKCJrbm93bkVNIiwgJ25JbmQnKSwgYygiZnJlcTEiLCAnbkluZDEnKSkKICAgIHNldG5hbWVzKGRmMiwgYygia25vd25FTSIsICduSW5kJyksIGMoImZyZXEyIiwgJ25JbmQyJykpCiAgICAKICAgIGRmIDwtIGRmMVtkZjIsIC4oY2hyb21vLCBwb3NpdGlvbiwgZnJlcTEsIGZyZXEyLCBuSW5kMSwgbkluZDIpXVshaXMubmEoZnJlcTEpICYgIWlzLm5hKGZyZXEyKSAmIGZyZXExID4gMC4xICYgZnJlcTIgPiAwLjEsIF0KICAgIGc9Z2Vuc1tpXQogICAgCiAgICBlc3ROZSROZVtpXTwtZGZbLCBqck5lMihmcmVxMSwgZnJlcTIsIG5JbmQxLCBuSW5kMiwgZyldIAoKICAgICMgYmxvY2sgYm9vdHN0cmFwcGluZyBhY3Jvc3MgTEdzCiAgICB1cS5jaCA8LSBkZlssIHNvcnQodW5pcXVlKGNocm9tbykpXQoKICAgIGJvb3QucmUgPC0gYm9vdCh1cS5jaCwganJOZTJibG9jaywgMTAwMCwgZ2VuID0gZywgYWxsZGF0YSA9IGRmKQogICAgZXN0TmUkbWVkaWFuW2ldPC1tZWRpYW4oYm9vdC5yZSR0W2lzLmZpbml0ZShib290LnJlJHQpXSkgIyBtZWRpYW4gYm9vdHN0cmFwCiAgICBlc3ROZSRtZWFuW2ldPC1tZWFuKGJvb3QucmUkdFtpcy5maW5pdGUoYm9vdC5yZSR0KV0pCiAgICBjaTwtYm9vdC5jaShib290LnJlLCB0eXBlID0gYygncGVyYycpKQogICAgIzk1JSBDLkkuCiAgICBlc3ROZSRDSS5sb3dbaV08LWNpJHBlcmNlbnRbNF0KICAgIGVzdE5lJENJLnVwW2ldPC1jaSRwZXJjZW50WzVdCiAgICAKICAgICNyZXNldCB0aGUgYXR0aWJ1dGVzCiAgICBzZXRuYW1lcyhkZjEsIGMoImZyZXExIiwgJ25JbmQxJyksYygia25vd25FTSIsICduSW5kJykpCiAgICBzZXRuYW1lcyhkZjIsIGMoImZyZXEyIiwgJ25JbmQyJyksYygia25vd25FTSIsICduSW5kJykpCn0KCndyaXRlLmNzdihlc3ROZSwiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc19TUy5jc3YiKQoKI2VzdE5lPC1yZWFkLmNzdigiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc19UQi5jc3YiLCByb3cubmFtZXMgPSAxKQplc3ROZSR5ZWFyPC1hcHBseShlc3ROZVsicG9wMiJdLDEsIGZ1bmN0aW9uKHgpIHtpZiAoeD09Ijk2IikgeD0xOTk2CiAgICAgICAgICAgICAgICAgICBlbHNlIGlmICh4PT0iMDYiKSB4PTIwMDYKICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHg9PSIxNyIpIHg9MjAxN30pCgpnZ3Bsb3QoZXN0TmVbYygxLDMpLF0sIGFlcyh4PXllYXIsIHk9TmUpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0yLCBjb2xvcj0iYmx1ZSIpKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IENJLmxvdywgeW1heCA9IENJLnVwKSwgd2lkdGggPSAwLjIsIGNvbG9yPSJibHVlIikrCiAgICBnZW9tX3BhdGgoY29sb3I9ImJsdWUiKSt5bGFiKCJFc3RpYW10ZWQgTmUiKSt4bGFiKCJZZWFyIikrCiAgICB0aGVtZV9jbGFzc2ljKCkrZ2d0aXRsZSgiU1MiKQpnZ3NhdmUoIi4uL091dHB1dC9OZS9Kb3JkZS1SeW1hbl9OZS5lc3RpbWF0ZXNfU1MucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQoKYGBgCiFbXSguLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzX1NTLnBuZykKCgoqIFBsb3QgMyBwb3B1bGF0aW9ucyB0b2dldGhlcgpgYGB7cn0KCm5lPC1kYXRhLmZyYW1lKCkKcG9wczwtYygiUFdTIiwiVEIiLCJTUyIpCmZvciAoaSBpbiAxOjMpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc18iLCBwb3BzW2ldLCIuY3N2IiksIHJvdy5uYW1lcyA9IDEpCiAgICBkZiRwb3A8LXBvcHNbaV0KICAgIG5lPC1yYmluZChuZSwgZGYpCn0KCm5lJHllYXI8LWFwcGx5KG5lWyJwb3AyIl0sMSwgZnVuY3Rpb24oeCkge2lmICh4PT0iOTYiKSB4PTE5OTYKICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHg9PTYpIHg9MjAwNgogICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoeD09NykgeD0yMDA3CiAgICAgICAgICAgICAgICAgICBlbHNlIGlmICh4PT0iMTciKSB4PTIwMTd9KQpuZTI8LW5lW2MoMSw0LDYsNywxMCwxMiwxMywxNSksXQpuZTIkcG9wPC1mYWN0b3IobmUyJHBvcCwgbGV2ZWxzPWMoIlRCIiwiUFdTIiwiU1MiKSkKCmdncGxvdChuZTIsIGFlcyh4PXllYXIsIHk9TmUsIGNvbG9yPXBvcCkpKwogICAgZ2VvbV9wb2ludChzaXplPTIpKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IENJLmxvdywgeW1heCA9IENJLnVwKSwgd2lkdGggPSAwLjIpKwogICAgZ2VvbV9wYXRoKCkreWxhYigiRXN0aWFtdGVkIE5lIikreGxhYigiWWVhciIpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzKQoKZ2dzYXZlKCIuLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzXzNQb3B1bGF0aW9ucy5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIGRwaT0zMDApCgpgYGAKCiFbXSguLi9PdXRwdXQvTmUvSm9yZGUtUnltYW5fTmUuZXN0aW1hdGVzXzNQb3B1bGF0aW9ucy5wbmcpCjxicj4KPGJyPgojIFBpIG51bGwgZGlzdHJpYnV0aW9uCgojIyAxLiBDcmVhdGUgcGVyc2l0ZSB0aGV0YS5wZXN0Lmd6IGZpbGVzIGluIGFuZ3NkCgpgYGB7YmFzaH0KCi9ob21lL2phbWNnaXJyL2FwcHMvYW5nc2QvbWlzYy90aGV0YVN0YXQgIHByaW50IC9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvdGhldGEvUFdTOTFfbWFmMDAudGhldGFzLmlkeCB8IGd6aXAgPiAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL3RoZXRhL1BXUzkxX21hZjAwX3RoZXRhcy5wZXN0UEcuZ3oKCiMgUnVuIHByaW50VGhldGEuc2ggYXQgZmFybQpgYGAKCgojIyAyLiBydW4gUiBzY3JpcHRzIGF0IGZhcm0gdG8gY3JlYXRlIG51bGwgZGlzdHJpYnV0aW9uIG9mIGdlbm9tZS13aWRlIHRoZXRhcwoKUnVuIGFuZ3NkX3RoZXRhX3NpdGVzaHVmZmxlX251bGwuc2ggYXQgZmFybSwgd2hpY2ggcnVucyBQaV9zaHVmZmxlX3B3cy5SIAogLSBUYWtlcyBsb25nIHRpbWUsIHNvIGNyZWF0ZSBhIHNjcmlwdCBmb3IgZWFjaCBwb3AueWVhciBjb21iaW5hdGlvbiBhbmQgcnVuIHNlcGFyYXRlbHkgCgpPdXRwdXQgZnJvbSB0aGV0YSBzaHVmZmxpbmcgcmVzdWx0cyBhcmUgaW4gRGF0YS9zaHVmZmxlL3RoZXRhLnNpdGVzaHVmZmxlLjUwMDAwLlBXUzkxX1BXUzk2LmNzdi5negoKCiMjIDMuIENhbGN1bGF0ZSBwLXZhbHVlcyB1c2luZyB0aGUgcmVzdWx0cyBmcm9tIHNodWZmbGluZyBhbmQgcGxvdCB0aGUgcmVzdWx0cyAgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojZnJvbSBjb2RFdm9sIGFuZ3NkX3RoZXRhX3NpdGVzaHVmZmxlX251bGxfc3RhdHMuUgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgbG9hZCBmdW5jdGlvbnMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnJlcXVpcmUoZGF0YS50YWJsZSkKcmVxdWlyZShwbHlyKQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUoUkNvbG9yQnJld2VyKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIHJlYWQgaW4gYW5kIHByZXAgZGF0YQojIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnllYXJzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCmNvbWI8LXQoY29tYm4oeWVhcnMsIDIpKQojIG1heCB0aGV0YSBwZXIgZ2Vub21lIGZyb20gcmVzaHVmZmxpbmcgKGFsbCBzaXRlcykgZnJvbSBhbmdzZF90aGV0YV9zaXRlc2h1ZmZsZV9udWxsLnIKCmNocm1heCA8LSBmcmVhZCgnLi4vRGF0YS9uZXdfdmNmL2Nocl9zaXplcy5iZWQnKQpjaHJtYXg8LWNocm1heFssLTJdCmNvbG5hbWVzKGNocm1heCk8LWMoImNociIsICJsZW4iKQpjaHJtYXgkc3RhcnQ8LWMoMCxjdW1zdW0oY2hybWF4JGxlbilbMToobnJvdyhjaHJtYXgpLTEpXSkKCmNocm1heCRlbmQ8LWN1bXN1bShjaHJtYXgkbGVuKQpjaHJtYXgkbWlkZGxlPC0oY2hybWF4JGVuZC1jaHJtYXgkc3RhcnQpLzIrY2hybWF4JHN0YXJ0Cgojc2V0a2V5KGNocm1heCwgY2hyKQoKI0Z1bmN0aW9ucyB0byBjYWxjdWxhdGUgcC12YWx1ZXMgZnJvbSBjb2RFdm9sCmNhbGNwRyA8LSBmdW5jdGlvbih0aGV0YWNoYW5nZSwgbnVsbCl7ICMgZm9yIGluY3JlYXNlcyBpbiB0aGV0YQogIHJldHVybigoc3VtKG51bGwgPiB0aGV0YWNoYW5nZSkrMSkvKGxlbmd0aChudWxsKSsxKSkgIyBlcXVhdGlvbiBmcm9tIE5vcnRoIGV0IGFsLiAyMDAyIEFtIEogSHVtIEdlbgp9CmNhbGNwTCA8LSBmdW5jdGlvbih0aGV0YWNoYW5nZSwgbnVsbCl7ICMgZm9yIGRlY3JlYXNlcyBpbiB0aGV0YQogIHJldHVybigoc3VtKG51bGwgPCB0aGV0YWNoYW5nZSkrMSkvKGxlbmd0aChudWxsKSsxKSkgIyBlcXVhdGlvbiBmcm9tIE5vcnRoIGV0IGFsLiAyMDAyIEFtIEogSHVtIEdlbgp9CgoKY29scyA8LSBicmV3ZXIucGFsKDQsICdQYWlyZWQnKVtyZXAoMToyLDEzKV0KRGF0YWxsPC1kYXRhLnRhYmxlKCkKZm9yIChwIGluIDE6IG5yb3coY29tYikpewogICAgIyBtYXggdGhldGEgcGVyIGdlbm9tZSBmcm9tIHJlc2h1ZmZsaW5nIChhbGwgc2l0ZXMpIGZyb20gYW5nc2RfdGhldGFfc2l0ZXNodWZmbGVfbnVsbC5yCiAgICBudWxsPC1mcmVhZChwYXN0ZTAoJy4uL0RhdGEvc2h1ZmZsZS90aGV0YS5zaXRlc2h1ZmZsZS41MDAwMC4nLCBjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSwnLmNzdi5neicpKQogICAgCiAgICAjdXBwZXIgYW5kIGxvd2VyIDk1JQogICAgbnVsbFssIC4odFdkX2w5NSA9IHF1YW50aWxlKG1pbnRXZCwgMC4wNSksIHRXZF91OTUgPSBxdWFudGlsZShtYXh0V2QsIHByb2JzID0gMC45NSksCiAgICAgICAgICAgICAgICB0UGRfbDk1ID0gcXVhbnRpbGUobWludFBkLCAwLjA1KSwgdFBkX3U5NSA9IHF1YW50aWxlKG1heHRQZCwgcHJvYnMgPSAwLjk1KSwKICAgICAgICAgICAgICAgIHREZF9sOTUgPSBxdWFudGlsZShtaW50RGQsIDAuMDUpLCB0RGRfdTk1ID0gcXVhbnRpbGUobWF4dERkLCBwcm9icyA9IDAuOTUpKV0KCiAgICAjYXNzaWduKHBhc3RlMCgibnVsbC4iLGNvbWJbcCwxXSwiXyIsY29tYltwLDJdKSwgbnVsbCkgICAgCiAgICAKICAgICMgc2xpZGluZyB3aW5kb3dzIHRoZXRhIGNoYW5nZSAoR0FUSyBzaXRlcykgZnJvbSBhbmdzZF90aGV0YV9zaXRlc2h1ZmZsZV9udWxsLnIKICAgIGRhdDwtZnJlYWQocGFzdGUwKCcuLi9EYXRhL3NodWZmbGUvdGhldGFfY2hhbmdlX3JlZ2lvbl81MDAwMC4nLCBjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSwnLmNzdi5neicpLCBkcm9wID0gMSkKICAgIGRhdFsscG9wOj1wYXN0ZTAoY29tYltwLDFdLCJfIixjb21iW3AsMl0pXQogICAgCiAgICBkYXQ8LW1lcmdlKGRhdCwgY2hybWF4WyxjKCJjaHIiLCJzdGFydCIpXSwgYnkueD0iQ2hyb21vIiwgYnkueSA9ICJjaHIiKQogICAgZGF0WywgUE9TZ2VuIDo9IFdpbkNlbnRlciArIHN0YXJ0XQogICAgZGF0WyxzdGFydCA6PSBOVUxMXSAjcmVtb3ZlIHN0YXJ0CiAgICAKICAgICNjYWxjdWxhdGUgcC12YWx1ZXMKICAgICMxLiB0aGV0YVcgbG9jaQogICAgZGF0W3RXZCA+IDAsIHRXZC5wIDo9IGNhbGNwRyh0V2QsIG51bGwkbWF4dFdkKSwgYnkgPSAuKENocm9tbywgV2luQ2VudGVyKV0gIyB0aGV0YVcgIGxvY2kKICAgIGRhdFt0V2QgPD0gMCwgdFdkLnAgOj0gY2FsY3BMKHRXZCwgbnVsbCRtaW50V2QpLCBieSA9IC4oQ2hyb21vLCBXaW5DZW50ZXIpXQogICAgIzIuIHRoZXRhIHBpCiAgICBkYXRbdFBkID4gMCwgdFBkLnAgOj0gY2FsY3BHKHRQZCwgbnVsbCRtYXh0UGQpLCBieSA9IC4oQ2hyb21vLCBXaW5DZW50ZXIpXSAjIHRoZXRhIHBpCiAgICBkYXRbdFBkIDw9IDAsIHRQZC5wIDo9IGNhbGNwTCh0UGQsIG51bGwkbWludFBkKSwgYnkgPSAuKENocm9tbywgV2luQ2VudGVyKV0KICAgIAogICAgI1RhamltYSdzIEQKICAgIGRhdFt0RGQgPiAwLCB0RGQucCA6PSBjYWxjcEcodERkLCBudWxsJG1heHREZCksIGJ5ID0gLihDaHJvbW8sIFdpbkNlbnRlcildICMgdGFqaW1hJ3MgRAogICAgZGF0W3REZCA8PSAwLCB0RGQucCA6PSBjYWxjcEwodERkLCBudWxsJG1pbnREZCksIGJ5ID0gLihDaHJvbW8sIFdpbkNlbnRlcildCgogICAgd3JpdGUuY3N2KGRhdCwgZmlsZT1nemZpbGUocGFzdGUwKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS90aGV0YV9zaXRlc2h1ZmZsZV8nLCBjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSwnLmNzdi5neicpKSkKICAgIAogICAgRGF0YWxsPC1yYmluZChEYXRhbGwsIGRhdCkKfQoKd3JpdGUuY3N2KERhdGFsbCwgZmlsZT1nemZpbGUocGFzdGUwKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS90aGV0YV9zaXRlc2h1ZmZsZV9QV1Nfc3VtbWFyeS5jc3YuZ3onKSkpCiAgIAoKIyMgUGxvdCB0aGUgcmVzdWx0cwoKI2Nocm9tb3NvbWUgbnVtYmVyIGxvY2F0aW9ucwp3aW5zeiA9IDVlNCAKCiNDaGFuZ2VzIGluIFBpIGJldHdlZW4geWVhcnMKRGF0YWxsJENocm9tbzwtZmFjdG9yKERhdGFsbCRDaHJvbW8sIGxldmVscz1jKHBhc3RlMCgiY2hyIiwxOjI2KSkpCkRhdGFsbCRwb3A8LWZhY3RvcihEYXRhbGwkcG9wLCBsZXZlbHM9YygiUFdTOTFfUFdTOTYiLCJQV1M5MV9QV1MwNyIsIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMDciLCJQV1M5Nl9QV1MxNyIsIlBXUzA3X1BXUzE3IikpCgpnZ3Bsb3QoRGF0YWxsLCBhZXMoUE9TZ2VuLCB0UGQvd2luc3osIGNvbG9yID0gQ2hyb21vKSkgKyAKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjMpICsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzLCBndWlkZT0ibm9uZSIpICsKICAgIHlsYWIoJ0NoYW5nZSBpbiBwaSBwZXIgc2l0ZScpK3hsYWIoIkNocm9tb3NvbWUiKSsKICAgIGdndGl0bGUoIkNoYW5nZXMgaW4gUGkiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9Y2hybWF4JG1pZGRsZSwgbGFiZWxzPTE6MjYpKwogICAgdGhlbWVfYncoKQpnZ3NhdmUocGFzdGUwKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS9DaGFuZ2VzX2luX1BpX1BXUy5wbmcnKSwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDksIGRwaSA9IDMwMCkKICAgIAojIHBsb3QgdGhldGFfV2F0ZXJzb24gY2hhbmdlCmdncGxvdChEYXRhbGwsIGFlcyhQT1NnZW4sIHRXZC93aW5zeiwgY29sb3IgPSBDaHJvbW8pKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scywgZ3VpZGU9Im5vbmUiKSArCiAgICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxKSArCiAgeWxhYignQ2hhbmdlIGluIFdhdHRlcnNvbnMgdGhldGEgcGVyIHNpdGUnKSt4bGFiKCJDaHJvbW9zb21lIikrCiAgZ2d0aXRsZSgiQ2hhbmdlcyBpbiBQaSIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl90aGV0YVdfUFdTLnBuZycsIHdpZHRoID0gNy41LCBoZWlnaHQgPSA5LCBkcGkgPSAzMDApCgojIHBsb3QgVGFqaW1hJ3MgRCBjaGFuZ2UKZ2dwbG90KERhdGFsbCwgYWVzKFBPU2dlbiwgdERkLCBjb2xvciA9IENocm9tbykpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGFscGhhID0gMC4zKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scyxndWlkZT0ibm9uZSIpICsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEpICsKICAgIHlsYWIoJ0NoYW5nZSBpbiBUYWppbWFzIEQgcGVyIHdpbmRvdycpK3hsYWIoIkNocm9tb3NvbWUiKSsKICAgIGdndGl0bGUoIkNoYW5nZXMgaW4gVGFqaW1hJ3MgRCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9UYWppbWFzRF9QV1MucG5nJywgd2lkdGggPSA3LjUsIGhlaWdodCA9IDksIGRwaSA9IDMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9QaV9QV1MucG5nKQoKIVtdKC4uL091dHB1dC9QaS9TaHVmZmxlL0NoYW5nZXNfaW5fdGhldGFXX1BXUy5wbmcpCgohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9UYWppbWFzRF9QV1MucG5nKQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBwbG90IHBpIHAtdmFsdWUgdnMuIHBvc2l0aW9uIApjb2xzIDwtIGJyZXdlci5wYWwoNCwgJ1BhaXJlZCcpW3JlcCgxOjIsMTMpXQpEYXRhbGwkQ2hyb21vPC1mYWN0b3IoRGF0YWxsJENocm9tbywgbGV2ZWxzPWMocGFzdGUwKCJjaHIiLDE6MjYpKSkKRGF0YWxsJHBvcDwtZmFjdG9yKERhdGFsbCRwb3AsIGxldmVscz1jKCJQV1M5MV9QV1M5NiIsIlBXUzkxX1BXUzA3IiwiUFdTOTFfUFdTMTciLCJQV1M5Nl9QV1MwNyIsIlBXUzk2X1BXUzE3IiwiUFdTMDdfUFdTMTciKSkKCmdncGxvdChEYXRhbGwsIGFlcyhQT1NnZW4sIC1sb2cxMCh0UGQucCkqc2lnbih0UGQpLCBjb2xvciA9IENocm9tbykpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAwLjIsIGFscGhhID0gMC4zKSArCiAgICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scywgZ3VpZGU9Im5vbmUiKSAreGxhYigiQ2hyb21vc29tZSIpKwogICAgeWxhYigibG9nMTAoUC12YWx1ZSkiKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBjb2xvciA9ICdncmV5JykgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBjb2xvciA9ICdncmV5JykrCiAgICBnZ3RpdGxlKCJQLXZhbHVlcyBmb3IgY2hhbmdlcyBpbiBQaSIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9QaS5zaXRlc2h1ZmZsZS5wLXZhbHVlc19QV1MucG5nJywgd2lkdGggPSA3LjUsIGhlaWdodCA9MTEsIHVuaXRzID0gJ2luJywgZHBpID0gMzAwKQoKCiMgcGxvdCB0aGV0YVcgcC12YWx1ZSB2cy4gcG9zaXRpb24gKGFsbCBsb2NpKQpnZ3Bsb3QoRGF0YWxsLCBhZXMoUE9TZ2VuLCAtbG9nMTAodFdkLnApKnNpZ24odFdkKSwgY29sb3IgPSBDaHJvbW8pKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMiwgYWxwaGEgPSAwLjMpICsKICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMsIGd1aWRlPSJub25lIikgK3hsYWIoIkNocm9tb3NvbWUiKSsKICAgIHlsYWIoImxvZzEwKFAtdmFsdWUpIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbG9nMTAoMC4wNSksIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIGNvbG9yID0gJ2dyZXknKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBjb2xvciA9ICdncmV5JykrCiAgICAgIGdndGl0bGUoIlAtdmFsdWVzIGZvciBjaGFuZ2VzIGluIFRoZXRhIikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWNocm1heCRtaWRkbGUsIGxhYmVscz0xOjI2KSsKICAgIHRoZW1lX2J3KCkKZ2dzYXZlKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS9DaGFuZ2VzX2luX3RoZXRhVy5zaXRlc2h1ZmZsZS5wLXZhbHVlc19QV1MucG5nJywgd2lkdGggPSA3LjUsIGhlaWdodCA9MTEsIHVuaXRzID0gJ2luJywgZHBpID0gMzAwKQoKI3Bsb3QgVGFqYW1hJ3MgRCBwLXZhbHVlIHZzLiBwb3NpdGlvbgpnZ3Bsb3QoRGF0YWxsLCBhZXMoUE9TZ2VuLCAtbG9nMTAodERkLnApKnNpZ24odERkKSwgY29sb3IgPSBDaHJvbW8pKSArIAogICAgZ2VvbV9wb2ludChzaXplID0gMC4yLCBhbHBoYSA9IDAuMykgKwogICAgZmFjZXRfd3JhcCh+cG9wLCBuY29sID0gMSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMsIGd1aWRlPSJub25lIikgK3hsYWIoIkNocm9tb3NvbWUiKSsKICAgIHlsYWIoImxvZzEwKFAtdmFsdWUpIikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBsb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAnZ3JleScpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAnZ3JleScpKwogICAgZ2d0aXRsZSgiUC12YWx1ZXMgZm9yIGNoYW5nZXMgaW4gVGFqaW1hJ3MgRCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9UYWppbWFELnNpdGVzaHVmZmxlLnAtdmFsdWVzX1BXUy5wbmcnLCB3aWR0aCA9IDcuNSwgaGVpZ2h0ID0xMSwgdW5pdHMgPSAnaW4nLCBkcGkgPSAzMDApCgpgYGAKCiFbXSguLi9PdXRwdXQvUGkvU2h1ZmZsZS9DaGFuZ2VzX2luX1BpLnNpdGVzaHVmZmxlLnAtdmFsdWVzX1BXUy5wbmcpCgoKIVtdKC4uL091dHB1dC9QaS9TaHVmZmxlL0NoYW5nZXNfaW5fdGhldGFXLnNpdGVzaHVmZmxlLnAtdmFsdWVzX1BXUy5wbmcpCgohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9UYWppbWFELnNpdGVzaHVmZmxlLnAtdmFsdWVzX1BXUy5wbmcpCgojIyA0LiBPdXRsaWVyIHJlZ2lvbnMgIAoKCmBgYHtyIGV2YWw9RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjCiMgcHJpbnQgb3V0bGllcnMKIyMjIyMjIyMjIyMjIyMjIyMKClBpX291dGxpZXJzPC1EYXRhbGxbdFBkLnAgPCAwLjA1LF0KVGhldGFfb3V0bGllcnM8LURhdGFsbFt0V2QucCA8IDAuMDUsXQpUYWppbWFEX291dGxpZXJzPC1EYXRhbGxbdERkLnAgPCAwLjA1LF0gI25vIG91dGxpZXJzCgpwaTwtZGF0YS5mcmFtZSh0YWJsZShQaV9vdXRsaWVycyRwb3AsIFBpX291dGxpZXJzJENocm9tbykpCnRoZTwtZGF0YS5mcmFtZSh0YWJsZShUaGV0YV9vdXRsaWVycyRwb3AsIFRoZXRhX291dGxpZXJzJENocm9tbykpCkQ8LWRhdGEuZnJhbWUodGFibGUoVGFqaW1hRF9vdXRsaWVycyRwb3AsIFRhamltYURfb3V0bGllcnMkQ2hyb21vKSkKCiNwbG90IFBXUzkxLTk2LCA5Ni0wNywgYW5kIDA3LTE3CnlyczwtYygiUFdTOTFfUFdTOTYiLCJQV1M5Nl9QV1MwNyIsIlBXUzA3X1BXUzE3IikKY29sMzwtYnJld2VyLnBhbCg0LCJQdVJkIilbMjo0XQoKcGkyPC1waVtwaSRWYXIxICVpbiUgeXJzLF0KcGkyJFZhcjE8LWZhY3RvcihwaTIkVmFyMSwgbGV2ZWxzPXlycykKZ2dwbG90KHBpMiwgYWVzKHg9VmFyMiwgeT1GcmVxLCBmaWxsPVZhcjEpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjgpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jb2wzKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdndGl0bGUoZXhwcmVzc2lvbihwYXN0ZSgiQ2hhbmdlcyBpbiAiLCBwaSkpKSsKICAgIHhsYWIoJycpK3lsYWIoJ051bWJlciBvZiByZWdpb25zIHdpdGggUDwwLjA1JykKZ2dzYXZlKCIuLi9PdXRwdXQvUGkvU2h1ZmZsZS9QaV9zaWduaWZpY2FudF9wZXJDaHJvbV9wZXJQb3AucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0LCBkcGk9MzAwKSAKCnRoMjwtdGhlW3RoZSRWYXIxICVpbiUgeXJzLF0KdGgyJFZhcjE8LWZhY3Rvcih0aDIkVmFyMSwgbGV2ZWxzPXlycykKZ2dwbG90KHRoMiwgYWVzKHg9VmFyMiwgeT1GcmVxLCBmaWxsPVZhcjEpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjgpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jb2wzKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdndGl0bGUocGFzdGUwKCJDaGFuZ2VzIGluIHRoZXRhIikpKwogICAgeGxhYignJykreWxhYignTnVtYmVyIG9mIHJlZ2lvbnMgd2l0aCBQPDAuMDUnKQpnZ3NhdmUoIi4uL091dHB1dC9QaS9TaHVmZmxlL1RoZXRhX3NpZ25pZmljYW50X3BlckNocm9tX3BlclBvcC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQsIGRwaT0zMDApIAoKRDI8LURbRCRWYXIxICVpbiUgeXJzLF0KRDIkVmFyMTwtZmFjdG9yKEQyJFZhcjEsIGxldmVscz15cnMpCmdncGxvdChEMiwgYWVzKHg9VmFyMiwgeT1GcmVxLCBmaWxsPVZhcjEpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjgpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jb2wzKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICBnZ3RpdGxlKHBhc3RlMCgiQ2hhbmdlcyBpbiBUYWppbWEncyBEIikpKwogICAgeGxhYignJykreWxhYignTnVtYmVyIG9mIHJlZ2lvbnMgd2l0aCBQPjAuMDUnKQpnZ3NhdmUoIi4uL091dHB1dC9QaS9TaHVmZmxlL1BpX3NpZ25pZmljYW50X3BlckNocm9tX3BlclBvcC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQsIGRwaT0zMDApIAoKYGBgCgohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvUGlfc2lnbmlmaWNhbnRfcGVyQ2hyb21fcGVyUG9wLnBuZykKCiFbXSguLi9PdXRwdXQvUGkvU2h1ZmZsZS9UaGV0YV9zaWduaWZpY2FudF9wZXJDaHJvbV9wZXJQb3AucG5nKQoKYGBge3IgZWNobz1UUlVFfQoKc3VtPC1kYXRhLmZyYW1lKHRhYmxlKFBpX291dGxpZXJzJHBvcCkpCnN1bTI8LWRhdGEuZnJhbWUodGFibGUoVGhldGFfb3V0bGllcnMkcG9wKSkKI3N1bTM8LWRhdGEuZnJhbWUodGFibGUoVGFqaW1hRF9vdXRsaWVycyRwb3ApKSBubyBvdXRsaWVycwoKc3VtPC1jYmluZChzdW0sIHN1bTIkRnJlcSkKY29sbmFtZXMoc3VtKTwtYygiUG9wcyIsICJQaSIsICJUaGV0YSIpCmtuaXRyOjprYWJsZSh0KHN1bSkpCmBgYAoKLSBNb3N0IGRpZmZlcmVuY2VzIGV4aXN0IGJldHdlZW4gMTk5NiBhbmQgMjAwNwotIENocjI1IGhhcyB0aGUgbW9zdCBzaWduaWZpY2FudCByZWdpb25zIGZvciBjaGFuZ2VzIGluIFBpIGFuZCBUaGV0YQpz